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

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

首先有一个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;
}
}

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

这就是抽象工厂模式。

最新文章

  1. C#之索引器
  2. ubuntu 安装配置jdk+eclipse+android sdk
  3. 矩阵卷积Matlab(转载)
  4. IOS应用程序多语言本地化解决方案
  5. 事件处理程序(addEventListener 和 attachEvent)
  6. zookeeper实现互斥锁
  7. HBASE学习笔记--shell
  8. 9.XML文件解析
  9. python excel操作总结
  10. flutter 容器 几种写法
  11. CentOS6.3上安装与配置nginx+php+mysql环境
  12. keil5到iar8的使用配置迁移
  13. ps流提取H264并解码播放
  14. 15. 迭代器模式(Iterator Pattern)
  15. Iris框架源码阅读和分析
  16. Nodejs学习事件模块
  17. Linux+Nginx+Asp.net Core及守护进程部署
  18. Python能做什么?
  19. 10分钟学会写Jquery插件
  20. pairs 和 ipairs区别

热门文章

  1. 使用hexdump 查看二进制文件
  2. squid 安装、配置、优化
  3. NSDateFormatter 问题
  4. C++ 过载,重写,隐藏
  5. Upcase 将edit1中的每个字符串改为首字母大写
  6. VS2005工程迁移到Eclipse CDT
  7. 【排障】编译安装Mysql并使用自启动脚本mysqld后报错
  8. tab选项卡
  9. [数据库]Oracle和mysql中的分页总结
  10. 基于ARM的RealView MDK开发环境