`

《Head.First设计模式》的学习笔记(5)--工厂方法模式

 
阅读更多

意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。

结构

image

实例:下面我们以Pizza店的例子来谈谈“工厂方法模式”的来龙去脉,我们学习的思路是“原始设计-->简单工厂-->工厂方法”。

情景分析:假如你有一个Pizza店,那么你的Pizza订单可能会写成如下代码(这段代码写在PizzaStore类里面):

 1public Pizza OrderPizza()
 2        {
 3            Pizza pizza = new Pizza();
 4            pizza.Prepare();
 5            pizza.Bake();
 6            pizza.Cut();
 7            pizza.Box();
 8            return pizza;
 9        }

10

如果你的Pizza店的Pizza有很多类,那么你的Pizza订单会如何写呢,可能会写成如下:

 1class PizzaStore
 2    {
 3        public Pizza OrderPizza(String paramPizzaType)
 4        {
 5            Pizza pizza = null;
 6            if (paramPizzaType.Equals("cheese"))
 7            {
 8                pizza = new CheesePizza();
 9            }

10            else if (paramPizzaType.Equals("greek"))
11            {
12                pizza = new GreekPizza();
13            }

14            else if (paramPizzaType.Equals("pepperon"))
15            {
16                pizza = new PepperoniPizza();
17            }

18            pizza.Prepare();
19            pizza.Bake();
20            pizza.Cut();
21            pizza.Box();
22            return pizza;
23        }

24
25        // 省略        
26    }

27

 上面的代码有一个问题:当Pizza的种类发生改变(或增加或减少)时,这段代码必须重写。那么这段代码应该如何改进呢?其实我们只要封装变化点就行了,即代码中的“if,else”语句。封装的过程如下:
1)、创建SimplePizzaFactory类。
2)、在SimplePizzaFactory类中创建CreatPizza方法。
3)、把“if,else”语句写道CreatPizza方法中。
相应的代码如下:

 1public class SimplePizzaFactory

 2    {

 3        public Pizza CreatPizza(String paramPizzaType)

 4        {

 5            Pizza pizza = null;

 6            if (paramPizzaType.Equals("cheese"))

 7            {

 8                pizza = new CheesePizza();

 9            }


10            else if (paramPizzaType.Equals("greek"))

11            {

12                pizza = new GreekPizza();

13            }


14            else if (paramPizzaType.Equals("pepperon"))

15            {

16                pizza = new PepperoniPizza();

17            }


18            return pizza;

19        }


20    }


21

 

这样做的好处:
1)、可以很好的达到代码重用。如果其他类想得到Pizza,都可以调用SimplePizzaFactory的CreatPizza()方法。
2)、维护方便。如果Pizza的创建需要改变,只需要改变CreatPizza()方法就行了,其他调用的地方不需要发生改变。
值得改进的地方
:可以把CreatPizza()写成静态方法。
改成静态方法的优点:不需要通过创建对象来使用类里的方法。
缺点:不能通过继承来改变创建对象的行为。
小结:
上面的代码其实是简单工厂模式的应用(简单工厂不是一个真正的模式)。
简单工厂(Simple Factory)模式的意图:Simple Factory模式根据提供给它的数据,返回几个可能类中的一个类的实例。通常它返回的类都有一个公共的父类和公共的方法。
结构:

image

工厂类角色Creator (SimplePizzaFactory):工厂类在客户端的直接控制下(Create方法)创建产品对象。
抽象产品角色Product (Pizza):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
具体产品角色ConcreteProduct (CheesePizza, GreekPizza,PepperoniPizza):定义工厂具体加工出的对象。
客户端Client(PizzaStore):负责调用SimplePizzaFactory的Create方法。
其实SimplePizzaFactory的CreatPizza()方法并没有符合面向对象的开闭原则,它没有对修改进行关闭,即当Pizza的种类改变时,这个方法必须重写,只不过改动的工作量减少了,只需要改动一处,其他调用的地方不需要变动而已。

新的需求
1)、Pizza店有了加盟店,加盟店生产Pizza的流程应该一成不变。
2)、每个加盟店可能要提供不同风味的Pizza(比如纽约、芝加哥、加州)。
按照简单工厂的方法,我们可以这样做:创建NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory类。相应的代码如下:

1NYPizzaFactory nyFactory = new NYPizzaFactory(); // 创建具有纽约风味的Pizza工厂
2            PizzaStore nyStore = new PizzaStore(nyFactory);  // 建立Pizza店,经营纽约风味的Pizza
3            nyStore.OrderPizza("cheese");                    // 订购具有纽约风味的CheesePizza

 如果需求不发生改变,那么用简单工厂就已经足够了,但是一旦需求发生了变化,简单工厂就不能适应了。

变化后的需求
1)、有些加盟店采用自创的流程,比如烘烤的做法有些差异(Bake方法改变)、不要切片(Cut方法不要)、采用其他公司的盒子(Box方法改变)等。
2)、Pizza的种类有可能发生改变(或增加或减少)。

我们的做法很简单,具体操作
1)、把SimpleFactory的CreatPizza()方法写回到PizzaStore里面。
2)、抽象PizzaStore,用NYPizzaStore、ChicagoPizzaStore等继承PizzaStore。
3)、具体的PizzaStore和具体的Pizza进行一一对应。

相应的类图如下(应用了工厂方法模式):

image 

说明:
1)、PizzaStore类是抽象类,相当于工厂方法模式的Creator类,NYPizzaStore类和ChicagoPizzaStore类继承了PizzaStore,相当于工厂方法模式的ConcreteCreator。
2)、Pizza是抽象类,相当于Product类,NYStyleCheesePizza类、NYStylePepperoniPizza类、 NYStyleGreekPizza类、ChicagoStyleCheesePizza类、ChicagoStylePepperoniPizza类、 ChicagoStyleGreekPizza类继承了Pizza类,相当于ConcreteProduct。
3)、NYPizzaStore类调用了NYStyleCheesePizza类、NYStylePepperoniPizza类、 NYStyleGreekPizza类,ChicagoPizzaStore类调用了ChicagoStyleCheesePizza类、 ChicagoStylePepperoniPizza类、ChicagoStyleGreekPizza类。

相应的代码如下:

Code

工厂方法模式的特点
1)、核心的工厂类不负责所有产品的创建,而是将具体创建工作交给子类去做,可以允许系统在不修改工厂角色的情况下引进新产品。
2)、工厂类与产品类往往具有平行的等级结构,它们之间一一对应。

工厂方法和简单工厂的区别
1)、Factory Method 的核心是一个抽象工厂类,而Simple Factory 把核心放在一个具体类上。
2)、Factory Method 的具体工厂类都有共同的接口,或者有共同的抽象父类。
3)、当系统扩展需要添加新的产品对象时,Factory Method仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而 Simple Factory 在添加新产品对象后不得不修改工厂方法,扩展性不好。

分享到:
评论

相关推荐

    Head.First 设计模式学习笔记.pdf

    ### Head.First 设计模式学习笔记知识点总结 #### 一、设计模式概述 设计模式是一种用于解决软件设计中常见问题的标准化方法。通过采用设计模式,开发者可以提高代码的复用性、灵活性和可维护性。《Head First 设计...

    HeadFirst 设计模式学习笔记1--策略模式Demo

    《HeadFirst设计模式学习笔记1--策略模式Demo》 在软件工程中,设计模式是一种解决常见问题的标准方案,它提供了一种在特定情况下组织代码的模板。策略模式是设计模式中的一种行为模式,它允许在运行时选择算法或...

    HeadFirst 设计模式学习笔记3--装饰模式 Demo

    在“HeadFirst 设计模式学习笔记3--装饰模式 Demo”中,作者通过实例讲解了装饰模式的基本概念、结构和应用场景。这篇文章可能是从CSDN博客平台上的一个链接访问的,遗憾的是,由于我们当前无法直接访问该链接,所以...

    HeadFirst 设计模式学习笔记2--观察者模式 demo

    总的来说,HeadFirst设计模式的学习笔记2关于观察者模式的演示,旨在帮助开发者理解如何使用观察者模式来构建可扩展的系统。通过实际的代码示例,我们可以更深入地掌握这一模式,并将其应用到日常开发中,提升代码的...

    HeadFirst设计模式学习笔记

    《HeadFirst设计模式学习笔记》是一份详尽的资料,旨在帮助读者深入理解并掌握设计模式这一编程领域的核心概念。设计模式是软件工程中的一种最佳实践,它在解决常见问题时提供了一种标准的解决方案,使得代码更易于...

    Head First设计模式读书笔记-DesignPatterns.zip

    《Head First设计模式》是一本深受开发者喜爱的设计模式学习书籍,它以易懂且生动的方式介绍了23种经典设计模式。这些模式是软件工程中经过实践验证的最佳实践,旨在提高代码的可重用性、可读性和可维护性。下面,...

    读书笔记:设计模式学习笔记和代码。《图解设计模式》《Head First 设计模式》.zip

    读书笔记:设计模式学习笔记和代码。《图解设计模式》《Head First 设计模式》

    Head First 设计模式学习笔记(十四)模式的组合使用

    在《Head First 设计模式学习笔记(十四)模式的组合使用》中,作者探讨了如何在实际编程中灵活地组合多种设计模式以解决复杂问题。这篇文章可能是基于《Head First 设计模式》这本书的一个章节,该书是设计模式领域...

    Head First 设计模式 扫描版

    《Head First 设计模式》是软件开发领域内一本广受欢迎的书籍,由Eric Freeman、Elisabeth Robson、Bert Bates和Kathy Sierra四位作者共同撰写。这本书以其独特的视觉风格和易于理解的教学方法,深入浅出地介绍了...

    Head First Servlets & JSP 学习笔记

    以上只是《Head First Servlets & JSP》一书中的部分核心知识点,实际内容还包括过滤器、监听器、MVC设计模式、JSTL等更广泛的主题,旨在帮助读者全面理解和掌握Servlet和JSP技术。通过深入学习,开发者能够构建高效...

    HeadFirst设计模式笔记

    《HeadFirst设计模式笔记》是深入理解软件设计思想的一份宝贵资料,主要涵盖了设计模式的基础理论和实际应用。设计模式是软件开发中的经验总结,它为解决常见的编程问题提供了标准的解决方案,使得代码更具可读性、...

    基于Java语言的《Head First 设计模式》学习笔记及实战练习源码

    本项目为《Head First 设计模式》的Java语言学习笔记与实战练习源码集合,包含104个文件,主要包括88个Java源文件、12个Markdown文档、3个XML配置文件及少量其他辅助文件。内容涵盖设计模式的学习笔记以及相应的代码...

    Head First Design Pattern 学习笔记

    著名的《Head First Design Pattern》学习笔记,摘要这本书中的设计思路。由于书本过长,整理出笔记帮助回想起设计模式。文件是docx格式,只能由OFFICE Word 2007之后的版本打开,内附Visio类图文件。本文由个人整理...

    head first 设计模式

    通过以上对“Head First设计模式”书中可能涉及的设计模式的介绍,我们可以看出这本书是学习面向对象设计模式的绝佳资源。无论是初学者还是有一定经验的开发人员,都能从中受益匪浅。理解并熟练运用这些模式能够帮助...

    head_first_servlet&jsp学习笔记

    【Servlet&JSP基础知识】 ...以上是`head_first_servlet&jsp`学习笔记的主要知识点,涵盖了Servlet和JSP的基础、Web应用架构、MVC模式、会话管理和JSP编程等多个方面,为深入理解和实践Servlet与JSP开发奠定了基础。

    LotusDomino学习笔记.doc

    ### LotusDomino学习笔记知识点概览 #### 1. 选取视图的列的内容 (@Trim @DbColumn) - **@Trim**: 是一个内置的LotusScript函数,用于去除字符串两端的空白字符。 - **@DbColumn**: 此函数用于获取指定列的信息。...

    head first策略者模式

    《Head First 策略者模式》学习笔记 策略者模式是一种行为设计模式,它使你能在运行时改变对象的行为。在软件开发中,我们常常遇到需要根据不同的情况执行不同算法的问题。策略者模式就是为了解决这类问题而生,它...

    head first C#学习笔记:如何创建事件

    本学习笔记将深入探讨如何在C#中创建事件,以实现一个棒球模拟系统的例子。在这个系统中,我们将关注投球手、观众和裁判的交互,当输入棒球的轨迹和距离时,这些对象会根据模拟结果做出相应的反应。 首先,理解事件...

Global site tag (gtag.js) - Google Analytics