[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式

[Head First设计模式]山西面馆中的设计模式——装饰者模式

[Head First设计模式]山西面馆中的设计模式——观察者模式

[Head First设计模式]山西面馆中的设计模式——建造者模式

引言

今天是冬至,去饺子馆吃饺子,看他们店里面的水饺种类挺多,在等待中,在想是不是可以用设计模式模拟一下,生产饺子的过程,正好最近也在看工厂模式,也就现学现卖了。当然,实现的方式很多,只是一个例子而已。祝大家冬至,多多吃水饺.....

对象创建的问题?

我们应该面向接口编程而不是面向实现编程,因为面向实现编程会使得我们的设计更脆弱,缺乏灵活性。但是我们每次使用new时,是不是正在违背这一设计原则呢?

当我们拥有一组相关的具体类时,是不是常常被迫写出类似下面的代码?

 1 Duck duck;
 2
 3 if(picnic){
 4
 5 duck=new MallardDuck();
 6
 7 }else if(hunting){
 8
 9 duck=new DecogDuck();
10
11 }else if(inBathTub){
12
13 duck=new RubberDuck();
14
15 }

(以上为伪代码,只为说明问题)

向上面的实例化过程,知道运行时我们才知道需要实例化哪个类。

这样做的后果是如果应用要做变化或扩展,往往要修改这段代码。这使得维护困难,并容易引入错误。

问题在哪儿?

出现上面那种问题,是不是new的问题呢?

从技术上来说,new并没有任何问题。new只是面向对象语言的最基本部分,真正的问题在于“变化”。

如果对接口编程,我们可以实现与许多“变化”的隔离,因为通过多态机制,我们的代码对于实现接口的新类依然适用。但是使用具体类麻烦就来了,因为增加新的具体类时相应的代码可能就必须修改?

怎么办?

面向对象的设计原则:识别变化的部分,并将与不变化的部分相分离。

书中Pizza店案例分析

PizzaStore类中的一段代码-订做pizza

 

修改后的代码

由于市场竞争,其他pizza店推出了新产品,我们也得增加!例如VeggiePizza。 GreekPizza最近不受欢迎,把它从菜单中取消。

于是。。。

 

分析:变与不变的部分

 

分离

我们将专管制作pizza的对象叫做Pizza工厂

Pizza工厂---SimplePizzaFactory

思考一下?

      这看来好像我们只是把问题从一个对象推给了另一个对象!这样做有什么好处?

      SimplePizzaFactory可以有许多个客户,这样,当实现改变时我们只需要修改SimplePizzaFactory,而不需修改众多的客户。 提高了聚合度,PizzaStore的职责是使用pizza对象, SimplePizzaFactory的职责是决定创建什么样的pizza对象。

用工厂重写PizzaStore类

 1 public class PizzaStore {
 2    SimplePizzaFactory factory;
 3    public PizzaStore(SimplePizzaFactory factory) {
 4        this.factory = factory;
 5    }
 6    public Pizza orderPizza(String type) {
 7         Pizza pizza;
 8         pizza=factory.createPizza(type);
 9         pizza.prepare();
10         pizza.bake();
11         pizza.cut();
12         pizza.box();
13         return pizza;
14    }
15    //other methods here
16 }

简单工厂模式

饺子馆中的简单工厂实现

 水饺要实现的接口

 1   /// <summary>
 2     /// 水饺要实现的接口
 3     /// </summary>
 4     public interface IDumpling
 5     {
 6         string DumplingName { get; }
 7         /// <summary>
 8         /// 水饺的准备阶段方法
 9         /// </summary>
10         void Prepare();
11         /// <summary>
12         /// 煮
13         /// </summary>
14         void Boild();
15         /// <summary>
16         /// 展示订单
17         /// </summary>
18         void Show();
19     }

具体的水饺类

 1  /// <summary>
 2     /// 猪肉大葱水饺类
 3     /// </summary>
 4     public class PorkAndScallionDumpling:IDumpling
 5     {
 6
 7         public string DumplingName
 8         {
 9             get { return "猪肉大葱水饺"; }
10         }
11
12         public void Prepare()
13         {
14             Console.WriteLine("准备猪肉茴香水饺25个");
15         }
16
17         public void Boild()
18         {
19             Console.WriteLine("正在煮......请稍等.....");
20         }
21
22         public void Show()
23         {
24             Console.WriteLine("您的{0},准备好了。", this.DumplingName);
25         }
26     }

 1 /// <summary>
 2     /// 猪肉茴香水饺类
 3     /// </summary>
 4     public class PorkAndFennelDumpling : IDumpling
 5     {
 6         public string DumplingName
 7         {
 8             get { return "猪肉茴香水饺"; }
 9         }
10
11         public void Prepare()
12         {
13             Console.WriteLine("准备猪肉茴香水饺25个");
14         }
15
16         public void Boild()
17         {
18             Console.WriteLine("正在煮......请稍等.....");
19         }
20
21         public void Show()
22         {
23             Console.WriteLine("您的{0},准备好了。", this.DumplingName);
24         }
25     }

工厂类

 1   /// <summary>
 2     /// 水饺的生产工厂
 3     /// </summary>
 4     public static class SimpleDumplingFactory
 5     {
 6         public static IDumpling CreateDumpling(string dumplingName)
 7         {
 8             IDumpling dumpling = null;
 9             switch (dumplingName)
10             {
11                 case "猪肉大葱":
12                     dumpling = new PorkAndScallionDumpling();
13                     break;
14                 case "猪肉茴香":
15                     dumpling = new PorkAndFennelDumpling();
16                     break;
17             }
18             return dumpling;
19         }
20     }

控制台代码

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             IDumpling dumpling = SimpleDumplingFactory.CreateDumpling("猪肉茴香");
 6             dumpling.Prepare();
 7             dumpling.Boild();
 8             dumpling.Show();
 9             Console.Read();
10         }
11     }

结果

授权pizza店

我们的pizza店非常成功,许多人都想开设我们的授权加盟店。为保证质量,我们希望他们使用我们经过时间考验的代码。
但是,不同地区的加盟pizza店可能希望供应不同口味的pizza。怎么解决这个问题呢?

解决方法之一:建立不同的工厂

 1 //建立不同的工厂:如NYPizzaFactory、 ChicagoPizzaFactory、 CaliforniaPizzaFactory,在PizzaStore中包含相应工厂的实例。其代码类似于:
 2 //该pizza店提供纽约风味的pizza
 3 NYPizzaFactory nyFactory=new NYPizzaFactory();//建立一个生产纽约风味pizza的工厂
 4 PizzaStore nyStore=new PizzaStore(nyFactory);//建立一个pizza店,引用纽约风味pizza的工厂
 5 nyStore.orderPizza(“Veggie”);//生产的是纽约风味的pizza
 6
 7 //该pizza店提供芝加哥风味的pizza
 8 ChicagoPizzaFactory chicagoFactory=new ChicagoPizzaFactory();
 9 PizzaStore chicagoStore=new PizzaStore(chicagoFactory);
10 chicagoStore.orderPizza(“Veggie”);

抽象工厂模式

这么多工厂,可以再增加抽象层
另一种解决方法-工厂方法模式

思路:改写的PizzaStore,将createPizza()方法放回到PizzaStore,但是声明为抽象方法,然后,为每一种地方风味创建一个PizzaStore的子类。

改造后的PizzaStore的代码

 1 public abstract class PizzaStore {
 2
 3    public Pizza orderPizza(String type) {
 4       Pizza pizza = createPizza(type);//在PizzaStore内调用自身的一个方法来制造pizza,而不是使用一个factory对象
 5
 6       pizza.prepare();
 7       pizza.bake();
 8       pizza.cut();
 9       pizza.box();
10       return pizza;
11      }
12     abstract Pizza createPizza(String type);//factory对象成了这里的一个抽象方法
13
14 }

下面我们需要PizzaStore的各种子类(对应不同的地区风味)

让子类做决定

 

 声明工厂方法

abstract Pizza createPizza(String type);
abstract Product factoryMethod(String type);

工厂方法是抽象的,在一个超类中定义。必须由子类来实现。
工厂方法返回一个产品,该产品通常在其所在类的方法中定义。(如orderPizza())
工厂方法通常提供参数,用以选择一个产品的不同品种。
工厂方法将客户(超类中的方法,如PizzaStore中的orderPizza())与具体的产品相隔离。

 工厂方法怎么工作?

假定张三喜欢纽约风味的pizza,李四喜欢芝加哥风味的pizza。
需要相应Pizza店的实例
调用orderPizza()订购想要的pizza品种
createPizza()被调用,并返回pizza到orderPizza()方法。
尽管不知道是什么pizza,但orderPizza()仍知道对它进行后续处理。

工厂方法模式中的类

创建者类 The Creator classes

产品类 The Product classes

工厂方法模式的定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式让一个类的实例化延迟到其子类。

工厂方法模式的结构

总结:Factory Method模式

意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式让一个类的实例化延迟到其子类。
别名
虚拟构造器

Factory Method—参与者

Product(document)定义工厂方法所创建对象的接口。
ConcreteProduct(mydocument)实现product接口。
Creator(application)声明工厂方法,可以调用工厂方法以创建一个product对象
ConcreteCreator (MyApplication)重新定义工厂方法,以返回一个ConcreteProduct实例

(篇幅有点长,关于工厂方法模式的实例就不再列举了,感兴趣的可以自己实现一下)

 参考书:

《First Head 设计模式》

 

博客地址: http://www.cnblogs.com/wolf-sun/
博客版权: 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
再次感谢您耐心的读完本篇文章。

转载:http://www.cnblogs.com/wolf-sun/p/3485805.html

时间: 2024-08-31 18:05:52

[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式的相关文章

实例讲解PHP设计模式编程中的简单工厂模式_php实例

简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简单工厂模式是由一个工厂对象决定创建出那一种产品类的实例. 1.工厂模式的几种形态工厂模式专门负责将大量有共同接口的类实例化.工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类.工厂模式有以下几种形态: (1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory Method Pattern). (2)工厂方法(Factory Meth

Ruby中使用设计模式中的简单工厂模式和工厂方法模式_ruby专题

之前有看过<ruby设计模式>,不过渐渐的都忘记了.现在买了一个大话设计模式,看起来不是那么枯燥,顺便将代码用ruby实现了一下. 简单工厂模式: # -*- encoding: utf-8 -*- #运算类 class Operation attr_accessor :number_a,:number_b def initialize(number_a = nil, number_b = nil) @number_a = number_a @number_b = number_b end d

以Java代码为例讲解设计模式中的简单工厂模式_java

1. 简单工厂模式简介简单工厂模式(Simple Factory),又被称为"静态工厂方法模式".它属于"创建模式"(创建对象的模式),并且是"工厂方法"模式的一种特殊实现. 通常,我们利用简单工厂模式来进行类的创建.例如,获取线程池对象,就是通过简单工厂模式来实现的.它的结构图如下所示: 工厂:工厂是简单工厂模式的核心,提供了对外接口.客户端或其它程序要获取Product对象,都是通过Factory的接口来获取的. 抽象产品:抽象产品是(许多)

PHP实现设计模式中的抽象工厂模式详解_php技巧

抽象工厂模式(Abstact Factory)是一种常见的软件设计模式.该模式为一个产品族提供了统一的创建接口.当需要这个产品族的某一系列的时候,可以为此系列的产品族创建一个 具体的工厂类. [意图] 抽象工厂模式提供一个创建一系统相关或相互依赖对象的接口,而无需指定它们具体的类[GOF95] [抽象工厂模式结构图] [抽象工厂模式中主要角色] 抽象工厂(Abstract Factory)角色:它声明一个创建抽象产品对象的接口.通常以接口或抽象类实现,所有的具体工厂类必须实现这个接口或继承这个类

详解iOS应用开发中使用设计模式中的抽象工厂模式_IOS

概述 我们知道简单工厂模式的优点是去除了客户端与具体产品的依赖,缺点是违反了"开放-关闭原则":工厂方法模式克服了简单工厂模式的缺点,将产品的创建工作放到具体的工厂类,每个工厂类负责生成一个产品.但是在实际应用中,一个工厂类只创建单个产品的情况很少,一般一个工厂类会负责创建一系列相关的产品,如果我们要设计这样的系统,工厂方法模式显然不能满足应用的需求,本章要介绍的抽象工厂模式,可以很好地解决一系列产品创建的问题. 定义 "提供一个创建一系列相关或相互依赖对象的接口,而无需指定

解析iOS应用开发中对设计模式中的抽象工厂模式的实现_IOS

概述抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广. 假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构.那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式.这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品. 通过使用抽象工厂模式,可以处理具有相同(或者相似)等级结构中的多个产品族中的产品对象的创建问题.如下图所示: 根据产品角色的结构图,就不难给出工厂角色的结构设计图. 可以看

Zend Framework中的简单工厂模式 图文_php技巧

前段时间用来ZF,把他当黑盒感觉不是很好,一直有看其源码的冲动,但是...如果一点一点点看的话,挑战确实有些大了.某天又然后想到好久没复习设计模式了.综合一下,复习一个设计模式之后在ZF中找一下使用这模式的源码吧,不读所有源码,读读比较"高级"的部分吧,要说模式,暂时不知道是不是所有模式ZF里面都有,但是应该有足够的模式够我最近看了,在说可以找找其他开源的软件来找模式.这段时间被各种笔试神马乱七八糟的把生活搞得稍微有点乱,但是不管怎样,复习还是必须的吧.再说一下ZF吧,ZF一个好处就是

Javascript设计模式理论与编程实战之简单工厂模式_javascript技巧

阅读目录 基本介绍 举例说明 总结说明 简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定的情况. 说的通俗点,就像公司茶水间的饮料机,要咖啡还是牛奶取决于你按哪个按钮. 简单工厂模式在创建ajax对象的时候也非常有用. 通常我们创建对象最常规的方法就是使用new关键字调用构造函数,这会导致对象之间的依赖性.工厂模式是一种有助于消除类之间依赖性的设计模式,它使用一个方法来决定要实例化哪一个

实例解析Java单例模式编程中对抽象工厂模式的运用_java

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 类型:创建类模式 类图: 抽象工厂模式与工厂方法模式的区别        抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象.他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构:而抽象工厂模式则是针对的多个产品等级结构.在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的