博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式
阅读量:5957 次
发布时间:2019-06-19

本文共 6033 字,大约阅读时间需要 20 分钟。

 系列文章

引言

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

对象创建的问题?

我们应该面向接口编程而不是面向实现编程,因为面向实现编程会使得我们的设计更脆弱,缺乏灵活性。但是我们每次使用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 here16 }

简单工厂模式

饺子馆中的简单工厂实现

 水饺要实现的接口

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

具体的水饺类

1  ///  2     /// 猪肉大葱水饺类 3     ///  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 ///  2     /// 猪肉茴香水饺类 3     ///  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   ///  2     /// 水饺的生产工厂 3     ///  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 设计模式》

 

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

你可能感兴趣的文章
JS声明语句提升与作用域
查看>>
非抢占式RCU实现(二),解释:为什么 RCU_NEXT_SIZE 宏值是4?
查看>>
在虚拟机的linux中利用VMware Tools实现与windows共享文件
查看>>
Windows下配置Java环境变量
查看>>
leetcode -- Candy
查看>>
几种减小javascript对性能影响的方法
查看>>
PHP常用库函数介绍+常见疑难问题解答
查看>>
ios 自定义UITableView中分组的标题sectionview
查看>>
Installing haproxy load balancing for http and https--转载
查看>>
iPhone-获取网络数据或者路径的文件名
查看>>
FORMAT格式
查看>>
启动Tomcat的时候遇到错误
查看>>
IE6,IE7浏览器下 margin 无效的解决方法
查看>>
SpringBoot读取application.properties文件
查看>>
hibernate 启动和辅助类实现资源的重复使用
查看>>
Mongodb快速入门之使用Java操作Mongodb
查看>>
js正则大扫除
查看>>
外省人员-办理护照_百度经验
查看>>
[实变函数]1.4 可数集合
查看>>
快速构建Windows 8风格应用19-基础控件II
查看>>