《Head First设计模式》第四章学习笔记
一、设计原则
要依赖抽象,不要依赖具体类。当你直接实例化一个对象时,就是在依赖它的具体类。
如果有一个不像是会改变的类,那么在代码中直接实例化具体类也就没什么大碍。
二、工厂模式
<一>、简单工厂模式
简单工厂模式:就是由一个类的方法(可以是静态方法)根据传入的参数,决定创建出哪一种具体产品类的实例。
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。类图如下:
<二>、工厂方法模式
工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
带参数的工厂方法,称为参数化工厂方法,它可以根据传入的参数创建不同的对象。(不推荐参数化的工厂方法,因为会导致每个具体的方法实现,跟简单工厂是一样的)
工厂方法类图如下:
抽象工厂类Creator,定义了一个创建对象的抽象方法factoryMethod,在每个具体的工厂类中,实现该方法,创建具体的产品实例。
<三>、抽象工厂模式
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不明确指定具体类。类图如下:
抽象工厂的每个方法,实际上看起来就是工厂方法。
三、例子
1、简单工厂模式的例子
披萨店做披萨,Pizza为披萨抽象类,CheesPizza、GreekPizza、ClamPizza等为具体的Pizza实现类。现在借助简单工厂模式,根据不同的参数,创建不同的披萨。代码片段如下:
简单工厂SimplePizzaFactory类:
public class SimplePizzaFactory {
public static Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new CheesePizza();
} else if ("greek".equals(type)) {
pizza = new GreekPizza();
} else if ("clam".equals(type)) {
pizza = new ClamPizza();
}
return pizza;
}
}
PizzaStore类(客户端):
public class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = SimplePizzaFactory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
测试代码:
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore store = new PizzaStore();
Pizza pizza = store.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName());
pizza = store.orderPizza("clam");
System.out.println("Joel ordered a " + pizza.getName());
}
}
2、工厂方法模式的例子
不同地区的披萨店,做的Pizza不一样。在工厂方法模式中,PizzaStore负责定义创建Pizza的方法,但方法的具体实现,由各个地区的披萨店来实现,并负责创建具体的Pizza。
抽象的工厂类:
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
// 抽象的方法,由各个子类来实现。此处用的是参数化的工厂方法
protected abstract Pizza createPizza(String type);
}
具体的工厂类:
public class ChicagoPizzaStore extends PizzaStore {
protected Pizza createPizza(String type) {
if ("cheese".equals(type)) {
return new ChicagoStyleCheesePizza();
}
return null;
}
}
具体的工厂类:
public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza(String type) {
if ("cheese".equals(type)) {
return new NYStyleCheesePizza();
}
return null;
}
}
测试例子:
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName());
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName());
}
}
3、抽象工厂的例子
4、JDK中工厂模式的应用
简单工厂:
- java.lang.Boolean#valueOf(String)
- java.lang.reflect.Proxy#newProxyInstance()
- java.lang.Class#forName()
- java.lang.Class#newInstance()
工厂方法:
- java.lang.Object#toString()
四、小结
1、在简单工厂模式中,一个工厂类处于对产品类实例化的中心位置上,它知道每一个产品,它决定哪一个产品类应当被实例化。这个模式的优点是允许客户端相对独立于产品创建的过程,并且在系统引入新产品的时候无需修改客户端,也就是说,它在某种程度上支持“开--闭”原则。但这个模式的缺点是对“开--闭”原则的支持力度不够,因为如果有新的产品加入到系统中去,就需要修改工厂类,将必要的逻辑加入到工厂类中。
2、在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。工厂方法模式退化后可以变得很像简单工厂模式:设想如果非常确定一个系统只需要一个具体工厂类,那么就不妨把抽象工厂给合并到具体的工厂类中。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
参考资料:
1、《Head First设计模式》 2、《java与模式》 3、JDK里的设计模式