工厂方法模式定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。(注:“决定”不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择了使用哪个子类,自然就决定了实际创建的产品是什么)

假设我们要开一间披萨店,提供不同口味的披萨。

首先有一个PizzaStore的类,里面提供一个orderPizza的方法,让客户选择要购买的Pizza。

最开始想到的是这样写:

public class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza = null;if(type.equals("cheese")) {pizza = new CheesePizza();} else if(type.equals("greek")){pizza = new GreekPizza();} else if(type.equals("pepperoni")){pizza = new PepperoniPizza();}pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
}

当披萨店增加比萨口味的时候,必须修改if else部分的代码,这样做没有对修改关闭。

所以,将代码会变化的部分提取出来,封装创建对象的代码到另一个类,就是SimplePizzaFactory。

public class SimplePizzaFactory {public Pizza createPizza(String type) {Pizza pizza = null;if(type.equals("cheese")) {pizza = new CheesePizza();} else if(type.equals("greek")){pizza = new GreekPizza();} else if(type.equals("pepperoni")){pizza = new PepperoniPizza();}return pizza;}
}

PizzaStore变成了:

public class PizzaStore {SimplePizzaFactory factory;public PizzaStore(SimplePizzaFactory factory) {this.factory = factory;}public Pizza orderPizza(String type) {Pizza pizza = null;pizza = factory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
}

问题:是否只是将问题搬到另一个对象?问题依然存在。

这样做有好处,SimplePizzaFactory可以有许多客户,不仅仅是PizzaStore,如果有一个类,PizzaShopMenu要求获得比萨的价格和描述,它只需与SimplePizzaFactory交互。所以,把创建比萨的代码包装进一个类,当以后实现改变时,只需要修改这个类即可。这就是简单工厂方法。

披萨店发展的很好,现在要在全球各地开分店,但不同区域的口味有差异,比如(纽约风味、芝加哥风味、加州风味)。

一种做法是,利用SimplePizzaFactory,写出三种不同的工厂NYPizzaFactory,ChicagoPizzaFactory、CaliforniaPizzaFactory。坏处是:比如在中国要开一个China风味的Pizza,要增加一个ChinaPizzaFactory的类,如果披萨的口味增加,比如增加一种不添加任何料的pizza,那么需要修改全部SimplePiizaFactory的子类。

另一种做法是,在实际中,不太可能单独划分不同工厂来生产不同披萨,而且,制造披萨一般是在披萨店现场制造的。那么就需要将制作披萨与披萨店绑定。

public abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza;pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}abstract Pizza createPizza(String type);
}

PizzaStore现在是一个抽象类,让NYStylePizzaStore,ChicagoStylePizzaStore,CaliforniaPizzaFactory继承PizzaStore实现各自的createPizza方法。让不同的披萨店(子类)来决定披萨的做法。坏处是:每增加一种披萨口味,要增加一个继承Pizza的子类和修改全部继承PizzaStore的子类的代码。这就是工厂方法。

现在为确保每家披萨店使用高质量原料,打算建造一家生产原料的工厂,并将原料运送到各家加盟店。问题是,不同地方的原料是不一样的,比如(芝加哥的人喜欢番茄酱料,纽约的人喜欢大蒜番茄酱料。

先定义一个原料工厂接口:

public interface PizzaIngredientFactory {public Dough createDough();public Sauce createSauce();public Cheese createCheese();public Veggies[] createVeggies();public Pepperoni createPepperoni();public Clams createClam();
}

现在可为不同区域的披萨店提供不同原料了:

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {public Dough createDough() {return new ThinCrustDough();}public Sauce createSauce() {return new MarinaraSauce();}public Cheese createCheese() {return new ReggianoCheese();}public Veggies[] createVeggies() {Veggies veggies[] = { new Garlic(), new  Onion(), new Mushroom(), new RedPepper() };return veggies;}public Pepperoni createPepperoni() {return new SlicedPepperoni();}public Clams createClam() {return new FreshClams();}
}

重做披萨类,使用我们的工厂生产的原材料:

public abstract class Pizza {String name;Dough dough;Sauce sauce;Veggies veggies[];Cheese cheese;Pepperoni pepperoni;Clams clam;abstract void perpare();        //现在perpare方法声明为抽象,这个方法实现收集特定pizza的原材料void bake() {System.out.println("Bake for 25 minutes at 350");}void cut() {System.out.println("Place pizza in official PizzaStore box");}void setName(String name) {this.name = name;}String getName() {return name;}public String toString() {System.out.println(name);}
}

一个Pizza类的子类:

public class CheesPizza extends Pizza {PizzaIngredientFactory ingredientFactory;    public CheesePizza(PizzaIngredientFactory i) {ingredientFactory = i;}void prepare(){    //现在不同的pizza实现不同的prepare方式System.out.println("Preparing " + name);dough = ingredientFactory.createDough();sauce = ingredientFactory.createSauce();cheese = ingredientFactory.createCheese();}
}

再回到披萨店:

public class NYPizzaStore extends PizzaStroe {public Pizza createPizza(String item) {Pizza pizza = null;PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();    //纽约店使用纽约的原料工厂if(item.equals("cheese")) {pizza = new CheesePizza(ingredientFactory);pizza.setName("New York Style Cheese Pizza");} else if(item.equals("veggie")) {pizza = new VeggiePizza(ingredientFactory);pizza.setName("New York Style Veggie Pizza");}......return pizza;}
}    

我们引入一个抽象工厂----原料生产工厂,通过抽象工厂接口,创建产品家族,利用这个接口写代码,就从实际工厂解耦,当增加另一个实际工厂,只需要让它实现这个接口。

这就是抽象工厂模式。

转载于:https://www.cnblogs.com/13jhzeng/p/5250169.html

工厂方法(Factory Pattern)相关推荐

  1. 设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)

    工厂模式 Factory Pattern(简单工厂.工厂方法.抽象工厂) 工厂模式-创建型模式-提供了创建对象的最佳方式. 在工厂模式中,创建对象时不会对客户端暴露创建逻辑,并且是通过一个共同的接口来 ...

  2. 设计模式(四)——工厂模式(Factory Pattern)

    工厂模式(Factory Pattern) 意义 工厂模式 实现了创建者和调用者的分离.将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦.从而提高项目的扩展和维护性 ...

  3. 设计模式 - 学习笔记 - 工厂模式Factory Pattern

    设计模式 - 学习笔记 - 工厂模式Factory Pattern 1. 简单工厂 1.1 应用场景 1.2 UML 1.3 优劣分析 好处 缺点 1.4 代码示例 抽象产品 AbstractProd ...

  4. 设计模式 ~ 创建型模式 ~ 工厂模式 ~ Factory Pattern。

    设计模式 ~ 创建型模式 ~ 工厂模式 ~ Factory Pattern. 文章目录 设计模式 ~ 创建型模式 ~ 工厂模式 ~ Factory Pattern. eg. 简单工厂模式. 结构. 优 ...

  5. Spring 通过工厂方法(Factory Method)来配置bean

    在spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. 在第一种利用bean config file(spring xml)方式中 ...

  6. [设计模式-创建型]工厂方法(Factory Method)

    概括 名称 Factory Method 结构 动机 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method 使一个类的实例化延迟到其子类. 适用性 当一个类不知道它所必 ...

  7. Java工厂方法---Factory Method

    工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类 工厂方法优点: 1.支持OCP原则,开闭原则,把创建产品的细节隐藏起来,对上层类的调用时透明的 2 ...

  8. 当Android遇上设计模式之工厂方法(Factory)模式

    文章目录 1. 简单工厂模式 2.1 定义 2.2 代码实现 2.3 使用场景 2. 工厂方法模式 2.1 定义 2.2 代码实现 2.3 使用场景 设计模式六大原则: 单一职责原则:就一个类仅有一个 ...

  9. Spring模式系列(二) 工厂模式(Factory Pattern) - 理解Spring的第一课

    factory pattern在spring的用法 Beanfactory spring框架最依赖的模式,没有之一 这也许是最多程序员使用过的模式之一,我也在我的项目中用过很多次.工厂模式贯穿于整个S ...

  10. 工厂方法 Factory Method

    背景:有一个应用框架,它可以向用户显示多个文档.在这个框架中,两个主要的抽象是类Application和Document.这两个类都是抽象的.客户必须通过它们的子类来做与举替应用相关的实现. 分析:因 ...

最新文章

  1. 常见面试题:为什么MySQL索引要用B+Tree呢?(看完你就能和面试官笑谈人生了)
  2. C++ Primer 5th笔记(chap 15 OOP)虚函数
  3. WIN7 下安装 SQL Server 2000 兼容性问题
  4. 处理时间_5_计算时间列所在年的周序号
  5. Promise对象的创建与使用
  6. linux十字符木马,Linux系统随机10字符病毒的清除
  7. Python小白的数学建模课-B2. 新冠疫情 SI模型
  8. linux nfs挂载域名,Linux系统挂载NFS的方法
  9. windows 配置squid反向代理服务器
  10. ios6.0_6.1_苹果手机_evasion_完美越狱
  11. PMP 风险应对措施 :规避和减轻的区别
  12. 关于央行新推数字货币的综述
  13. 微博营销的价值与注意点
  14. 梯形图请用c语言,简单使用C语言写梯形图精简V2.0.pdf
  15. Elasticsearch Sliced Scroll分页检索案例分享
  16. Unity的Package了解(2020.3)
  17. 18在protel DXP中PCB图中给电路板绘制边框、安装孔的方法介绍成都电路板设计
  18. 手机测血氧Android应用,手机也能监测血氧饱和度?华为这个黑科技太实用了
  19. java通过电话号码获取归属地,区号,邮编
  20. 谷粒商城异步编排(三十二)

热门文章

  1. java计算两个数组的交集_回顾面试题:计算两个数组交集
  2. centos mysql5.6.35_centos6.8 mysql 5.6.35 glibc安装
  3. db2 查看表结构_数据库结构文档的生成利器
  4. 运用div css和java_如何将css应用于div模式
  5. HTTPS是对称加密还是非对称加密?
  6. linux数据向量化指令,不充分SIMD向量化技术研究.PDF
  7. linux 嵌入式 人工智能,嵌入式人工智能有哪些相关技术
  8. python类的构造方法和assert的使用,用MethodType动态绑定类方法
  9. 生成对抗网络的损失函数如何设计_如何检测极小人脸?试试超分辨率
  10. c语言 消除最后一个空格,新人提问:如何将输出时每行最后一个空格删除