工厂模式(Factory)
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
new
按照之前的原则,使用接口,并 new 一个具体实现:
Duck duck = new MallardDuck();
但如果出现一堆相关的具体类时,可能会写出这样的代码:
Duck duck;
if (picnic) { // 在野外,是绿头鸭
duck = new MallardDuck();
} else if (hunting) { // 在打猎,是诱导鸭
duck = new DecoyDuck();
} else if (inBathTub) { // 在浴缸,是橡皮鸭
duck = new RubberDuck();
}
一旦有变化或扩展,就要重新打开这段代码进行检查和修改。通常这样修改过的代码将造成部分系统更难维护和更新,而且也更容易犯错。
栗子
假设有一家比萨店,店里的披萨是这样的:
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("装上盒子...");
}
}
菜单上有不同的披萨口味:
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";
}
}
订单系统的代码是这样的:
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 的代码抽出来。
简单工厂
把不同口味的披萨放到披萨工厂里,由工厂根据客户的需求生产:
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;
}
}
乍一看,只是将代码转到另一个地方了,其实不然,对于披萨工厂来说,它可以面向其他的客户,比如其他小吃店,而不是限制在这间披萨店。
重写比萨店的订单代码:
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;
}
}
拓展比萨市场
现在比萨店要开分店了,比如在纽约,芝加哥等地方,而不同地方的比萨口味会有点不同,比如纽约的披萨皮薄,少芝士,而芝加哥的皮厚,多芝士。
// 继承自简单工厂的纽约披萨工厂
NYPizzaFactory nyFactory = new NYPizzaFactory();
// 纽约披萨分店
PizzaStore nyStore = new PizzaStore(nyFactory);
// 纽约风味的芝士披萨
nyStore.orderPizza("cheese");
ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore chicagoStore = new PizzaStore(chicagoFactory);
chicagoStore.orderPizza("cheese");
未完待续……