new 的问题
每当你使用 new 实例化一个具体的类时,那这就是一种实现而不是接口,而具体的实现会导致代码脆弱并且不灵活。
从技术上说,new 没有问题。问题在于需求不断变化,而这些变化又会影响 new 的使用。所以该如何解决问题呢?
以 Pizza 店为例
假设你有一家 pizza 店,你有很多种 pizza,可能就会写下这样的代码:
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;
}
每当新加一种 pizza 时,都需要改变上面的 if 块,这对于维护人员来说太痛苦了!
这时需要利用一个设计原则:
identify the aspects that vary and seperate them from what stays the same.
于是我们把中间那段创建很多不同对象的代码移除,放到一个新的对象中去,这个对象一般叫做工厂(Factory),工厂专门解决对象创建的细节。现在可以画出这样一个图:
现在假设你已经打败了其他竞争者,全国都开有分店,但是不同的地方需要不同的口味。有一种方法来解决这样的问题:把前面提到的工厂删掉,然后根据地方创建工厂,比如:CaliforniaPizzaFactory, ChicagoPizzaFactory, NYPizzaFactory。最后把 PizzaStore 和最合适的工厂结合在一起,就万事大吉了。就像这样:
但是,这么做,你就完全控制不了这些当地工厂的生产行为。那究竟应该如何在保持灵活性的同时,可以控制行为呢?
pizza 店的一个框架
现在把 createPizza() 方法放回 PizzaStore 类中,但这次是一个抽象方法,然后再根据地区创建子类。
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);
}
现在创建 NYPizzaStore
// 纽约地区 pizza
public class NYPizzaStore extends PizzaStore
{
Pizza createPizza(String item)
{
if (item.equals("cheese")) return new NYStyleCheesePizza();
else if (item.equals("veggie")) return new NYStyleVeggiePizza();
else if (item.equals("clam")) return new NYStyleClamPizza();
else if (item.equals("pepperoni")) return new NYStylePepperoniPizza();
else return null;
}
}
之后类似的创建 ChicagePizzaStore 和 CaliforniaPizzaStore。
最后完整的代码参见 Factory Pattern—Github
最后看看工厂模式
All factory patterns encapsulate object creation. The Factory Method Pattern encapsulates object creation by letting subclasses decide what objects to create.
直观的图形表示:
现在下一个正式定义:
The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
上面的定义说 Factory Method 让子类决定实例化哪个类,这里的决定并不是指子类在 runtime 决定,而是指 creator 类并不知道创建了哪些真正的 product ,product 的创建完全是由使用的子类的选择所决定。
As in the official definition, you’ll often hear developers say that the Factory Method lets subclasses decide which class to instantiate. They say decides not because the pattern allows subclasses themselves to decide at runtime, but because the creator class is written without knowledge of the actual products that will be created, which is decided purely by the choice of the subclass that is used.
这里提出一个新的设计原则 Dependency Inversion Principle:
Depend upon abstractions. Do not depend upon concrete classes.
这一原则看上去和
Program to an interface, not an implementation.
很像。但是他的要求更强,这条原则建议高层次组件和低层次组件都依赖于抽象,而不是高层次依赖于低层次。工厂模式能够满足这一原则。