前言:按照惯例我以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设计模式——简单工厂、工厂、抽象工厂的更多相关文章

  1. Java设计模式之-----工厂模式(简单工厂,抽象工厂)

    一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...

  2. 设计模式--简单工厂VS工厂VS抽象工厂

    前几天我一直在准备大学毕业生,始终绑起来,如今,终于有时间去学习设计模式.我们研究今天的话题是植物三口之家的设计模式的控制--简单工厂VS工厂VS抽象工厂. 经过细心推敲,我们不难得出:工厂模式是简单 ...

  3. Java设计模式(三) 抽象工厂模式

    原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...

  4. PHP设计模式(三)抽象工厂模式(Abstract Factory)

    一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...

  5. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

  6. &lt;十一&gt;读&lt;&lt;大话设计模式&gt;&gt;之抽象工厂模式

    学习设计模式有一段时间了,对设计模式有一个体会,就是没那么难.就是设计程序遵循一些原则,让代码可复用,在改动的时候不用涉及太多的类,扩展方便.抽象工厂模式名字听起来抽象.但理解起来一点也不抽象,用语言 ...

  7. Java的设计模式(4)--抽象工厂模式

    提供一个创建一系列或相互依赖对象的接口,而无须指定他们具体的类.例如某些系统可能需要为用户提供一系列相关对象,但系统不希望用户直接使用new运算符实例化这些对象,而是应当由系统来控制这些对象的创建,否 ...

  8. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录

    1楼留头头大神:http://www.cnblogs.com/toutou/p/4899388.html   v阅读目录 v写在前面 v简单工厂模式 v工厂方法模式 v抽象工厂模式 v博客总结 v博客 ...

  9. Head First 设计模式 --4 工厂模式 抽象工厂模式

    (用到了依赖倒置原则) 我们写的代码中,有的时候可能会出现根据外面给定的不同的参数在方法中根据参数实例化不同的实例,就是会根据不同的参数会new出不同的实例.如果这么写了,这段代码会非常的脆弱,一旦出 ...

随机推荐

  1. 虚拟现实中自由步行(free-space walking)

    之前我们讲到了虚拟现实中漫游方式的分类.虚拟现实中的漫游(travel/navigate)方式,即是应用提供给用户的,在虚拟环境中移动的方式.虚拟现实的漫游方式中,有一种被称为“完全动作线索”1,即用 ...

  2. http转换为https

    1.下载ssl 证数 百度ssl 证数都有 其中以便宜ssl为例子 注册登陆 选择免费版 可以使用3个月: 申请过程中需要检测该域名是否为本人所有 ,所以邮箱检测或者域名配置 很简单检测就好了: 验证 ...

  3. [Redis] Redis的基本数据结构

    key-value 通过key获取或设置value SET key value GET key SET server:name "fido" GET server:name SET ...

  4. Windows10+YOLOv3实现检测自己的数据集(1)——制作自己的数据集

    本文将从以下三个方面介绍如何制作自己的数据集 数据标注 数据扩增 将数据转化为COCO的json格式 参考资料 一.数据标注 在深度学习的目标检测任务中,首先要使用训练集进行模型训练.训练的数据集好坏 ...

  5. egret引擎中使用tiled运行在微信小游戏中

    egret的官方文档,对tiled的介绍不是很细致,很多东西都需要摸索.现在把踩的坑记录下来.作为一个备忘 引用tiledmap的库 在GitHub上下载egret的tiledmap支持库:https ...

  6. gorilla/mux类库解析

    golang自带的http.SeverMux路由实现简单,本质是一个map[string]Handler,是请求路径与该路径对应的处理函数的映射关系.实现简单功能也比较单一: 不支持正则路由, 这个是 ...

  7. Linux配置python

    文章出处  https://www.cnblogs.com/yhongji/p/9383857.html 我这里使用的时centos7-mini,centos系统本身默认安装有python2.x,版本 ...

  8. 不依赖远程API启动SEER区块链命令行钱包和网页钱包的方法

    不依赖远程API启动命令行钱包和网页钱包的方法 在SEER的见证人操作等需要使用命令行钱包的操作中,我们介绍了通过钱包连接远程API来和区块链交互的方法.类似这样: cli_wallet.exe -s ...

  9. windows下bower init 报错: bower ENOINT Register requires an interactive shell

    windows下bower初始化时不应该在git bash中,而应该在cmd下打开的dos窗口中进行

  10. 基于STL的堆略解

    什么是STL 以下内容摘自这儿. STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.它是由Alexander Stepanov.Meng Le ...