设计模式:工厂方法模式(Factory method)

一、问题

在前一章中通过披萨的实例介绍了简单工厂模式。在披萨实例中,如果我想根据地域的不同生产出不同口味的披萨,如纽约口味披萨,芝加哥口味披萨。如果利用简单工厂模式,我们需要两个不同的工厂,NYPizzaFactory、ChicagoPizzaFactory。在该地域中有很多的披萨店,他们并不想依照总店的制作流程来生成披萨,而是希望采用他们自己的制作流程。这个时候如果还使用简单工厂模式,因为简单工厂模式是将披萨的制作流程完全承包了。那么怎么办?

二、解决方案

我们可以这样解决:将披萨的制作方法交给各个披萨店完成,但是他们只能提供制作完成的披萨,披萨的订单处理仍然要交给披萨工厂去做。也就是说,我们将createPizza()方法放回到PizzaStore中,其他的部分还是保持不变。

三、基本定义

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式让实例化推迟到子类。

四、模式结构

工厂方法模式的UML结构图:

  Product:抽象产品。所有的产品必须实现这个共同的接口,这样一来,使用这些产品的类既可以引用这个接口。而不是具体类。

ConcreteProduct:具体产品

 Creator:抽象工厂。它实现了所有操纵产品的方法,但不实现工厂方法。Creator所有的子类都必须要实现factoryMethod()方法。

ConcreteCreator:具体工厂。制造产品的实际工厂。它负责创建一个或者多个具体产品,只有ConcreteCreator类知道如何创建这些产品。

 工厂方法模式是简单工厂模式的延伸。在工厂方法模式中,核心工厂类不在负责产品的创建,而是将具体的创建工作交给子类去完成。也就是后所这个核心工厂仅仅只是提供创建的接口,具体实现方法交给继承它的子类去完成。当我们的系统需要增加其他新的对象时,我们只需要添加一个具体的产品和它的创建工厂即可,不需要对原工厂进行任何修改,这样很好地符合了“开闭原则”。

五、工厂方法模式实现

针对上面的解决方案,得到如下UML结构图:

抽象产品类:Pizza.java

public abstract class Pizza {    protected String name;        //名称    protected String dough;       //面团    protected String sause;       //酱料    protected List<String> toppings = new ArrayList<String>();       //佐料

    public void prepare() {        System.out.println("Preparing " + name);        System.out.println("Tossing dough");        System.out.println("Adding sause");        System.out.println("Adding toppings");        for (int i = 0; i < toppings.size(); i++) {            System.out.println("   " + toppings.get(i));        }    }

    public void bake() {        System.out.println("Bake for 25 minutes at 350");    }

    public void cut() {        System.out.println("Cutting the pizza into diagonal slices");    }

    public void box() {        System.out.println("Place pizza in official PizzaStore box");    }

    public String getName() {        return name;    }}

具体产品类:NYStyleCheesePizza.java

public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza() {        name = "Ny Style Sauce and Cheese Pizza";        dough = "Thin Crust Dough";        sause = "Marinara Sauce";

        toppings.add("Crated Reggiano Cheese");    }

}

ChicagoStyleCheesePizza.java

public class ChicagoStyleCheesePizza extends Pizza {    public ChicagoStyleCheesePizza() {        name = "Chicago Style Deep Dish Cheese Pizza";        dough = "Extra Thick Crust Dough";        sause = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");    }

    public void cut() {        System.out.println("Cutting the Pizza into square slices");    }}

抽象工厂:披萨总店。PizzaStore.java

public abstract class PizzaStore {    public Pizza orderPizza(String type){        Pizza pizza;        pizza = createPizza(type);

        pizza.prepare();        pizza.bake();        pizza.cut();        pizza.box();

        return pizza;    }

    /*     * 创建pizza的方法交给子类去实现     */    abstract Pizza createPizza(String type);}

具体工厂。披萨分店。NYPizzaStore.java

public class NYPizzaStore extends PizzaStore {

    @Override    Pizza createPizza(String item) {        Pizza pizza = null;        if ("cheese".equals(item)) {            pizza = new NYStyleCheesePizza();        }        /**         else if("veggie".equals(item)){         pizza = new NYStyleVeggiePizza();         }         else if("clam".equals(item)){         pizza = new NYStyleClamPizza();         }         else if("pepperoni".equals(item)){         pizza = new NYStylePepperoniPizza();         }         */

        return pizza;    }}

ChicagoPizzaStore.java

public class ChicagoPizzaStore extends PizzaStore {    Pizza createPizza(String type) {        Pizza pizza = null;        if ("cheese".equals(type)) {            pizza = new ChicagoStyleCheesePizza();        }        /**         else if("clam".equals(type)){         pizza = new ChicagoStyleClamPizza();         }         else if("pepperoni".equals(type)) {         pizza = new ChicagoStylePepperoniPizza();         }         else if("veggie".equals(type)){         pizza = new ChicagoStyleVeggiePizza();         }         */        return pizza;    }

}

做了这么多,应该可以吃披萨了吧。Ethan要一份纽约口味的披萨,Joel需要芝加哥口味的披萨。

PizzaTestDrive.java

public class PizzaTestDrive {    public static void main(String[] args) {        System.out.println("---------Joel 需要的芝加哥的深盘披萨---------");        ChicagoPizzaStore chicagoPizzaStore = new ChicagoPizzaStore();       //建立芝加哥的披萨店        Pizza joelPizza = chicagoPizzaStore.orderPizza("cheese");             //下订单        System.out.println("Joel ordered a " + joelPizza.getName() + "\n");

        System.out.println("---------Ethan 需要的纽约风味的披萨---------");        NYPizzaStore nyPizzaStore = new NYPizzaStore();        Pizza ethanPizza = nyPizzaStore.orderPizza("cheese");        System.out.println("Ethan ordered a " + ethanPizza.getName() + "\n");

    }}

运行结果。

---------Joel 需要的芝加哥的深盘披萨---------
Preparing Chicago Style Deep Dish Cheese Pizza
Tossing dough
Adding sause
Adding toppingsShredded Mozzarella Cheese
Bake for 25 minutes at 350
Cutting the Pizza into square slices
Place pizza in official PizzaStore box
Joel ordered a Chicago Style Deep Dish Cheese Pizza---------Ethan 需要的纽约风味的披萨---------
Preparing Ny Style Sauce and Cheese Pizza
Tossing dough
Adding sause
Adding toppingsCrated Reggiano Cheese
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
Ethan ordered a Ny Style Sauce and Cheese Pizza

  

六、工厂方法模式的优缺点

优点

1、  在工厂方法中,用户只需要知道所要产品的具体工厂,无须关系具体的创建过程,甚至不需要具体产品类的类名。

2、  在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。

缺点

1、  每次增加一个产品时,都需要增加一个具体类和对象实现工厂,是的系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

七、工厂方法适用场景

1、一个类不知道它所需要的对象的类。在工厂方法模式中,我们不需要具体产品的类名,我们只需要知道创建它的具体工厂即可。

2、一个类通过其子类来指定创建那个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

3、将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。

七、总结

         1、工厂方法模式完全符合“开闭原则”。

         2、工厂方法模式使用继承,将对象的创建委托给子类,通过子类实现工厂方法来创建对象。

         3、工厂方法允许类将实例化延伸到子类进行。

         4、工厂方法让子类决定要实例化的类时哪一个。在这里我们要明白这并不是工厂来决定生成哪种产品,而是在编写创建者类时,不需要知道实际创建的产品是哪个,选择了使用哪个子类,就已经决定了实际创建的产品时哪个了。

         5、在工厂方法模式中,创建者通常会包含依赖于抽象产品的代码,而这些抽象产品是、由子类创建的,创建者不需要真的知道在制作哪种具体产品。

posted on 2019-05-02 19:56  shoshana~ 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/shoshana-kong/p/10803219.html

设计模式:工厂方法模式(Factory method)相关推荐

  1. 【设计模式】工厂方法模式 Factory Method Pattern

    在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...

  2. 工厂方法模式(Factory Method)简介

    工厂方法模式 名字 跟已经介绍的 简单工厂模式很类似. 实际上它们的模型也是十分相似的. 我们先看看工厂模式的定义. 一. 工厂方法(Factory Method)模式定义 教材上是这样写的: 工厂方 ...

  3. 设计模式之六:工厂方法模式(Factory method Pattern)

    工厂方法(Factory Method)模式就是定义一个创建对象的工厂接口,将实际创建工作推迟到子类当中. 核心工厂类不再负责具体产品的创建,仅提供了具体工厂子类必须实现的接口,这样核心类成为一个抽象 ...

  4. 设计模式之工厂方法模式(Factory Method)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式包括:1.FactoryMethod(工厂方法模式):2.Abstract Factory(抽象工厂模式):3.Sin ...

  5. 设计模式之工厂方法模式---factory method

    模式的介绍 模式的定义 Define an interface for creating an object,but let subclassed decide which class to inst ...

  6. 设计模式之工厂方法模式(Factory Method Pattern)

    一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...

  7. 软件工程 - 设计模式学习之工厂方法模式Factory Method

    在现实生活中我们可以看见,乐事在卖薯片,可比克也在卖. 我敢肯定的说它们各自都有自己的工厂来生产薯片,而且生产出来的薯片味道还是不一样的. 这就是我们这里所谓的工厂方法模式. 我们来看看这个模式的UM ...

  8. 设计模式题目-工厂方法模式(Factory Method)

    设计一个程序来读取多种不同存储格式的图片,针对每一种图片格式都设计一个图片读取器(ImageReader),如GIF格式图片读取器(GifReader)用于读取GIF格式的图片,JPEG格式图片读取器 ...

  9. 设计模式-工厂方法(Factory Method)

    2018-1-20 by Atlas 设计思想 核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被 ...

  10. C++实现工厂方法模式Factory Method Pattern

    设计原则6:要依赖抽象,不要依赖具体类.(又称依赖倒置原则Dependency Inversion Principle) 不能让高层组件依赖低层组件,而且,不管高层组件或低层组件,两者都应该依赖于抽象 ...

最新文章

  1. mysql 添加table_mysql数据库对table的增删改查
  2. Educational Codeforces Round 13 E. Another Sith Tournament 状压dp
  3. Unknown system variable 'tx_isolation'] with root cause
  4. C#字节数组与值类型变量的互相转换,以及注意事项
  5. 3.1集合相关知识点
  6. pat 乙级 1029 旧键盘(C++)
  7. MyBatis动态传入表名,字段名参数的解决办法
  8. 斗地主AI算法——第十三章の主动出牌(2)
  9. android webview的使用问题
  10. 国庆海报没有灵感,给你设计要点素材!
  11. 知识表示学习 TransE 代码逻辑梳理 超详细解析
  12. 【UML】构件图(Component Diagram)
  13. JavaScript日历1
  14. 1005打印任务取消不了 hp_hp打印机无法取消打印的文档解决方法(最新整理)
  15. word文档如何在方框内打钩
  16. 蓝宝石(Al2O3)晶体基片
  17. 【个人提升】如何克服惰性
  18. YApi接口管理平台远程代码执行漏洞(含批量POC)
  19. 深圳FC1511型号单片机应用程序编程开发环境MCU
  20. Design pattern : Singleton

热门文章

  1. 软考中级之数据库系统(重点)
  2. Fastjson 漏洞分析
  3. Visual Studio 2019 编译Firefox 68.0.1
  4. STM32F10x_硬件I2C主从通信(轮询发送,中断接收)
  5. 音频(二) - AudioRecordAudioTrack
  6. ArcGIS河网提取及淹没区分析
  7. 谷歌浏览器登录不上 sarai浏览器可以登录的问题
  8. JPA - @Convert属性映射转换器
  9. Python正则表达式实例详解
  10. “Windows 资源保护找到了损坏文件但无法修复其中某些文件”的问题