工厂模式(Factory)
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
new
按照之前的原则,使用接口,并 new 一个具体实现:
1
| Duck duck = new MallardDuck();
|
但如果出现一堆相关的具体类时,可能会写出这样的代码:
1 2 3 4 5 6 7 8 9
| Duck duck;
if (picnic) { duck = new MallardDuck(); } else if (hunting) { duck = new DecoyDuck(); } else if (inBathTub) { duck = new RubberDuck(); }
|
一旦有变化或扩展,就要重新打开这段代码进行检查和修改。通常这样修改过的代码将造成部分系统更难维护和更新,而且也更容易犯错。
栗子
假设有一家比萨店,店里的披萨是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| abstract class Pizza { protected String name;
public void prepare() { System.out.println("擀揉面皮,加佐料..."); }
public void bake() { System.out.println("烘烤一段时间..."); }
public void cut() { System.out.println("切几刀..."); }
public void box() { System.out.println("装上盒子..."); } }
|
菜单上有不同的披萨口味:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class CheesePizza extends Pizza { public CheesePizza() { this.name = "cheese"; } }
class GreekPizza extends Pizza { public GreekPizza() { this.name = "greek"; } }
class PepperoniPizza extends Pizza { public PepperoniPizza() { this.name = "pepperoni"; } }
|
订单系统的代码是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class PizzaStore { public Pizza orderPizza(String type) { Pizza pizza;
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; } }
|
出现的正是上面提到的问题,既然这部分容易变化,那么可以把这段 new 的代码抽出来。
简单工厂
把不同口味的披萨放到披萨工厂里,由工厂根据客户的需求生产:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class SimplePizzaFactory { public Pizza createPizza(String type) { Pizza pizza;
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; } }
|
乍一看,只是将代码转到另一个地方了,其实不然,对于披萨工厂来说,它可以面向其他的客户,比如其他小吃店,而不是限制在这间披萨店。
重写比萨店的订单代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class PizzaStore { SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; }
public Pizza orderPizza(String type) { Pizza pizza = factory.createPizza(type);
pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box();
return pizza; } }
|
拓展比萨市场
现在比萨店要开分店了,比如在纽约,芝加哥等地方,而不同地方的比萨口味会有点不同,比如纽约的披萨皮薄,少芝士,而芝加哥的皮厚,多芝士。
1 2 3 4 5 6 7 8 9 10
| NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("cheese");
ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory(); PizzaStore chicagoStore = new PizzaStore(chicagoFactory); chicagoStore.orderPizza("cheese");
|
未完待续……