Head First设计模式——简单工厂、工厂、抽象工厂
前言:按照惯例我以Head First设计模式的工厂模式例子开始编码学习。并由简单工厂,工厂模式,抽象工厂模式依次演变,归纳他们的相同与不同。
话说Head First认为简单工厂并不是设计模式,而是一种编程习惯,但并不妨碍我们使用它,接下来我们对工厂模式一探究竟。
1、披萨店例子
首先我们要开一个披萨店,对于业务不复杂的情况下我们可以快速的开发出一个披萨店以及订购披萨的逻辑
public Pizza OrderPizza() {
Pizza pizza = new Pizza();
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
}
public class Pizza {
//准备
public void Prepare() { }
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
}
如果我们有更多的披萨种类可能需要将Pizza定义成抽象类 在订单里面根据订购的披萨种类返回不同的披萨,我们对披萨进行抽象并改造Order。
public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza=null;
if (type == "cheese")
{
pizza = new CheesePizza();
}
else if (type == "viggie") {
pizza = new VeggiePizza();
}
//else if ......
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public abstract class Pizza
{
//准备
public void Prepare() { }
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
} //奶酪披萨
public class CheesePizza : Pizza
{
}
//素食披萨
public class VeggiePizza : Pizza
{
}
到这里我们可能想到了,如果增加披萨种类或者移除披萨那么我们将对披萨店进行修改。
设计原则对扩展开放,对修改关闭。我们需要将创建披萨的变化封装起来。对此弄出来一个专门创建披萨的“工厂“类。
并采用静态,这样就不需要实例化对象,也遵循了不对实现编程原则。
public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza = SimplePizzaFactory.CreatePizza(type); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public static class SimplePizzaFactory {
public static Pizza CreatePizza(string type) {
Pizza pizza = null;
if (type == "cheese")
{
pizza = new CheesePizza();
}
else if (type == "viggie")
{
pizza = new VeggiePizza();
}
return pizza;
}
}
这样将创建披萨简单的封装起来即是简单工厂(静态工厂),简单工厂也可以不用静态类,但简单工厂并不是一种专门的设计模式(有时候可能会混淆,认为这即是”工厂模式“),更像是我们平时编程都会做的一种习惯。我们将改动封装在一个局部当有变化的时候只需要修改这个工厂类。
2、更多的披萨店
现在我们要开更多的披萨店,例如美国风格披萨店(USSytlePizzaStore)、中国风格披萨店(CHNSytlePizzaStore)。
我们可以采用简单工厂模式,创建两个不同风格的披萨工厂,然后创建两个不同风格的披萨店,不同风格的披萨店使用对应的披萨工厂来获取。
但是我们此时的变化点是披萨店。我们希望披萨店的结构或者流程是按照一定规则的,只是不同风格的披萨。此时我们有更好的解决办法:工厂模式。
接下来我们看如何实现
public abstract class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza= CreatePizza(type); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
} public abstract Pizza CreatePizza(string type);
} public class USSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "cheese")
{
pizza = new USStyleCheesePizza();
}
else if (type == "viggie")
{
pizza = new USStyleVeggiePizza();
}
return pizza;
}
} public class CHNSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "cheese")
{
pizza = new CHNStyleCheesePizza();
}
else if (type == "viggie")
{
pizza = new CHNStyleVeggiePizza();
}
return pizza;
}
} //US奶酪披萨
public class USStyleCheesePizza : Pizza
{
}
//US素食披萨
public class USStyleVeggiePizza : Pizza
{
} //CHN奶酪披萨
public class CHNStyleCheesePizza : Pizza
{
}
//CHN素食披萨
public class CHNStyleVeggiePizza : Pizza
{
}
由实现我们可以看到我们将PizzaStore修改成抽象类,不同的披萨店继承抽象类返回自己不同风格的披萨。
这样设计后当增加产品,我们也只是在具体的子类披萨店中修改其中的披萨创建,不会影响披萨店本身流程和其他披萨店的实现。
工厂方法模式:定义了一个创建对象的接口,由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
工厂方法与简单工厂的区别:工厂方法的子类看起来很像简单工厂。简单工厂把全部的事情在一个地方处理完成,而工厂方法却是创建一个框架,让子类决定如何实现。
3、披萨的不同原料
不同风格的披萨店有不同风格的披萨,而这些披萨的不同风格是来自不同原料造成,所以不同风格的披萨变化的部分是材料。
我们先建造原料和原料工厂,以中国披萨原料工厂为例
//披萨原料工厂接口
public interface PizzaIngredientFactory {
public Veggie CreateVeggie();
public Cheese CreateCheese();
}
//具体工厂实现
public class CNHPizzaIngredientFactory : PizzaIngredientFactory
{
public Cheese CreateCheese()
{
return new CHNCheese();
} public Veggie CreateVeggie()
{
return new CHNVeggie();
}
} public abstract class Veggie
{
}
public class USVeggie : Veggie {
}
public class CHNVeggie : Veggie {
} public abstract class Cheese
{
}
public class USCheese : Cheese
{
}
public class CHNCheese : Cheese
{
}
然后重做Pizza
public abstract class Pizza
{
public String Name;
Veggie veggie;
Cheese cheese;
//准备
public abstract void Prepare();
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
}
加入了原料的抽象 Veggie 和 Cheese,同时我们让Prepare变成抽象方法,让他的具体子类决定用什么材制造不同风格的披萨。接着我们重做子类,以CheesePizza为例
//奶酪披萨
public class CheesePizza : Pizza
{
PizzaIngredientFactory IngredientFactory;
public CheesePizza(PizzaIngredientFactory IngredientFactory) {
this.IngredientFactory = IngredientFactory;
}
public override void Prepare()
{
IngredientFactory.CreateCheese();
}
}
修改中国披萨店
public class CHNSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
//创建中国原材料工厂
CNHPizzaIngredientFactory ingredientFactory = new CNHPizzaIngredientFactory();
if (type == "cheese")
{
pizza = new CheesePizza(ingredientFactory);
}
else if (type == "viggie")
{
pizza = new VeggiePizza(ingredientFactory);
}
return pizza;
}
}
通过这一系列的改造我们引入了新类型的工厂,也就是所谓的抽象工厂,抽象工厂用来创造原料。
利用抽象工厂我们代码将从实际工厂解耦,这样如果我们的工厂需要扩展那么我们则可在子类中进行修改扩展。
工厂方法与抽象工厂的异同优缺点
相同:都是用来创建对象。
不同:工厂方法使用的是继承,抽象工厂使用的是组合。
优点:工厂方法只负责从具体类型中解耦,抽象工厂适合将一群相关的产品集合起来。
缺点:抽象工厂扩展接口需要修改每个子类。
Head First设计模式——简单工厂、工厂、抽象工厂的更多相关文章
- Java设计模式之-----工厂模式(简单工厂,抽象工厂)
一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...
- 设计模式--简单工厂VS工厂VS抽象工厂
前几天我一直在准备大学毕业生,始终绑起来,如今,终于有时间去学习设计模式.我们研究今天的话题是植物三口之家的设计模式的控制--简单工厂VS工厂VS抽象工厂. 经过细心推敲,我们不难得出:工厂模式是简单 ...
- Java设计模式(三) 抽象工厂模式
原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...
- PHP设计模式(三)抽象工厂模式(Abstract Factory)
一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- <十一>读<<大话设计模式>>之抽象工厂模式
学习设计模式有一段时间了,对设计模式有一个体会,就是没那么难.就是设计程序遵循一些原则,让代码可复用,在改动的时候不用涉及太多的类,扩展方便.抽象工厂模式名字听起来抽象.但理解起来一点也不抽象,用语言 ...
- Java的设计模式(4)--抽象工厂模式
提供一个创建一系列或相互依赖对象的接口,而无须指定他们具体的类.例如某些系统可能需要为用户提供一系列相关对象,但系统不希望用户直接使用new运算符实例化这些对象,而是应当由系统来控制这些对象的创建,否 ...
- 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录
1楼留头头大神:http://www.cnblogs.com/toutou/p/4899388.html v阅读目录 v写在前面 v简单工厂模式 v工厂方法模式 v抽象工厂模式 v博客总结 v博客 ...
- Head First 设计模式 --4 工厂模式 抽象工厂模式
(用到了依赖倒置原则) 我们写的代码中,有的时候可能会出现根据外面给定的不同的参数在方法中根据参数实例化不同的实例,就是会根据不同的参数会new出不同的实例.如果这么写了,这段代码会非常的脆弱,一旦出 ...
随机推荐
- CMD的最佳“代替品”
让CMD成为历史 Windows用户大多都使用过"cmd",cmd被称为"阉割版"的DOS系统~ 很多用户除此之外,还喜欢Linux命令行~但是CMD的命令和L ...
- [一]基本sqlplus命令
基本sqlplus命令: 1: sqlplus scott/tiger ; #简化连接数据库 2:show user; #想知道当前登陆的用户是哪一位 3:conn 用户名[/密码] [AS SYSD ...
- 从零开始的vue学习笔记(二)
数据与方法 当一个 Vue 实例被创建时,它将 data 对象中的所有的属性加入到 Vue 的响应式系统中.data的数据和视图同步更新. 实例创建后添加一个新的属性,对这个属性的的改动将不会触发任何 ...
- Scala 学习笔记之集合(4)
集合的模式匹配操作: object CollectionDemo5 { def main(args: Array[String]): Unit = { //集合模式匹配1 val ls = List( ...
- 常用css总结
个人博客: https://chenjiahao.xyz 1.让网站快速变灰 html { filter: grayscale(100%);//IE浏览器 -webkit-filter: graysc ...
- Spring5源码解析5-ConfigurationClassPostProcessor (上)
接上回,我们讲到了refresh()方法中的invokeBeanFactoryPostProcessors(beanFactory)方法主要在执行BeanFactoryPostProcessor和其子 ...
- C++学习笔记-预备知识
1.1 C++简介 C++融合3种不同的编程方式:C语言代表的过程性语言.C++在C语言基础上添加的类代表的面向对象语言.C++模板支持的广泛编程. 1.2 C++简史 1.2.1 C语言 Ritch ...
- Java 语言特点
引入<Java核心技术:Ⅰ> 1. 简单性 Java 语法是 C++ 语法的一个“ 纯净” 版本.这里没有头文件. 指针运算(甚至指 针语法).结构. 联合.操作符重载. 虚基类等.如果你 ...
- Nmon安装
下载对应系统的nomn工具(我用centos6.5_64位下载的是nmon_linux_14i.tar.gz) mkdir /nmon cd /nmon 导入nmon的tar.gz包解压 tar -z ...
- jquery 获取input的值
$("input").attr("value") -- 获取的是input的默认值 $("input").val() ...