一、问题

在前一章《设计模式读书笔记-----简单工厂模式》中通过披萨的实例介绍了简单工厂模式。在披萨实例中,如果我想根据地域的不同生产出不同口味的披萨,如纽约口味披萨,芝加哥口味披萨。如果利用简单工厂模式,我们需要两个不同的工厂,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{@OverridePizza 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");}
}

运行结果。

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

        优点

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

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

缺点

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

七、工厂方法适用场景

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

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

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

七、总结

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

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

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

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

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

设计模式读书笔记-----工厂方法模式相关推荐

  1. 设计模式学习笔记——工厂(Factory)模式

    设计模式学习笔记--工厂(Factory)模式 @(设计模式)[设计模式, 工厂模式, factory] 设计模式学习笔记工厂Factory模式 基本介绍 工厂案例 类图 实现代码 framework ...

  2. Java 设计模式之静态工厂方法模式

    设计模式系列 创建型设计模式 Java 设计模式之单例模式 Java 设计模式之静态工厂方法模式 Java 设计模式之工厂方法模式 Java 设计模式之抽象工厂模式 Java 设计模式之Builder ...

  3. 手撕设计模式之「工厂方法模式」(Java描述)

    前言 工厂方法模式是对简单工厂模式的改进,它通过对工厂类进行抽象形成一个抽象工厂接口,再让具体的工厂负责对应产品的创建,使得在增加产品的场景中也满足"开闭原则".希望通过本文的学习 ...

  4. 设计模式学习-工厂方法模式

    在上文(设计模式学习-简单工厂模式)的模拟场景中,我们用简单工厂模式实现了VISA和MASTERARD卡的刷卡处理,系统成功上线并运行良好,突然有一天老大跑来说,我们的系统需要升级,提供对一般银联卡的 ...

  5. 设计模式----创建型设计模式(单例模式、工厂方法模式、构建者模式)

    创建型设计模式 单例模式(Singleton Pattern) 单例模式介绍 代码演示 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线程不安全) 懒汉式(线程安全,同步方法) 懒汉式(线程安全, ...

  6. 【设计模式学习】工厂方法模式

    cpp学习设计模式:工厂方法模式 在学习工厂方法模式之前,先回忆前面学的简单工厂模式: 简单工厂模式就是将对象的创建和逻辑的判断都交给了一个工厂类去做,这样做的优点是客户端不需要知道具体产品类的类名和 ...

  7. 设计模式系列之 工厂方法模式

    定义 定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类.工厂方法让类的实例化推迟到子类中进行. 该定义是对生产者一方的描述,涉及四种角色,包括接口.接口实现类.被实例化的类.抽象产品(隐 ...

  8. 设计模式C++实现——工厂方法模式

    模式定义: 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个. 工厂方法让类把实例化推迟到子类. 模式结构: Creator是一个类,它实现了全部操纵产品的方法,但不实现工厂方法 ...

  9. 设计模式之四:工厂方法模式(披萨店生产披萨模拟流程)

    工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类.(披萨店生产披萨模拟流程) 工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象的过程封 ...

最新文章

  1. SWFUpload上传
  2. 网络流量队列优先级相关知识点
  3. linux下面mysql不监听3306
  4. ipv4地址是几位二进制数_知识点| ip地址详解,小学生都看的懂
  5. 【实践】文本相关性和知识蒸馏在知识蒸馏中的应用实践
  6. ASP.NET AjaxPro的应用 .AjaxPro使用中“XXX未定义”的一种解决方法(转载的)
  7. python gevent async_详解python之协程gevent模块
  8. 详解:知乎如何使用机器学习,未来还有哪些想象空间
  9. 千万要避免的五种程序注释方式
  10. Oracle中判断字段是否为数字
  11. 6. PHP bcompiler
  12. 苹果企业级开发者账号申请详解
  13. GoLand No Tests Were Run : 不能使用 fmt.Printf() BUG
  14. 7-45 航空公司VIP客户查询 【哈希表 链地址法】
  15. java中斜杠/和反斜杠\
  16. 节省60%费用!巧用阿里云归档存储降低基因测序成本
  17. 离散对数和椭圆曲线加密原理
  18. java vips_Java IConfigManager.getAllVIPs方法代碼示例
  19. 排序算法之一 冒泡排序(Bubble Sort)
  20. HD Tune中的各种信息表示的含义

热门文章

  1. android:visibility的VISIABLE,INVISIABLE,GONE的区别
  2. linux部署webgoat
  3. 人工智能和ChatGPT深度学习相关资源列表
  4. 域控禁用计算机网络,域控禁用usb接口 域控制器如何禁用usb端口的方法
  5. jQuery实现元素的隐藏和显示
  6. 线特征---LBD算法(三)
  7. ACM模板(快速幂、数论、图论)
  8. Python hasattr() 函数
  9. 英伟达数据被盗后续:黑客用证书将病毒伪装成显卡驱动
  10. 计算机考试小报怎么做,电脑小报的制作教案