背景:
前面提到,我们不应该针对实现编程,而应该针对接口编程,但我们每次new一个对象时,都是在针对实现编程。
Duck duck = new MallardDuck();
我们使用了接口让代码更具有弹性,但是还是得建立具体的实例,当有一堆相关具体类时,通常会写出这样的代码:
Duck duck;
if (picnic) {
duck = new MallardDuck();
} else if (hunting) {
duck = new DecoyDuck();
} else if () {
duck = new RubberDuck();
}
一旦有变化或者扩展,就必须重新打开这段代码进行检查和修改,这使得系统很难维护和更新。
设计:
new本身没错,真正有问题的是改变。针对接口编程,可以隔离掉以后系统可能发生的一大推改变。如果代码时针对接口而写,那么通过多态,它可以与任何新类实现该接口。但如果代码使用大量的具体类,等于自找麻烦,因为一旦加入新的具体类,就必须改代码。也就是说,你的代码并非“对扩展开放,对修改关闭”。
原则一:找出变化的部分,把他们从不变的部分分离出来;
实现一:把pizza的种类分离出来,把pizza的制作过程保留下来
实现:
public class PizzaStore {
SimplePizzaStore factory;
// 把变化的分离出来
public PizzaStore(SimplePizzaStore factory) {
this.factory = factory;
}
// 不变的留在这里
Pizza orderPizza(String type) {
Pizza pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new CheesePizza();
} else if ("greek".equals(type)) {
pizza = new GreekPizza();
} else if ("pepperoni".equals(type)) {
pizza = new PepperoniPizza();
}
return pizza;
}
}
似乎看起来只是把问题转移到了另一个地方,在代码变化过程中依然会改变原有的代码,但是别忘了除了orderPizza(),还有很多其他的客户,比如PizzaShopMenu、HomeDelivery等,我们把Pizza代码包装起来,以后只需改变这一个类即可。
总结:
简单工厂并不是一个“真正的”设计模式,更像是一种编程习惯。
接下来会介绍两个重量级的模式:工厂方法和抽象工厂。