目录
1. 简单工厂
1.1 定义
1.2 简单工厂样例代码
1.3 UML类图
1.3 语法特点
1.4 应用场景
1.5 简单工厂在JDK源码中的应用
2. 工厂方法模式
2.1 定义
2.2 工厂方法的示例代码
2.3 UML类图
简单工厂模式通过代码可以相当直接的看出个所以然,所以下文直接以样例来说明其相关特性,以下例子总结自HeadFirst设计模式一书;
假设有一个比萨店,创建不同类型比萨的过程都需要经过prepare、bake、cut、box等过程,那么则可以设计一个抽象的Pizza超类,其他不同类型的比萨继承自该超类并根据自身的需要决定是否需要重写超类的方法。
public class PizzaStore {
public Pizza orderPizza(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();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
由上面的例子知道,根据type创建比萨是改变的部分,因此可将其抽取出来放到一个专门负责创建比萨的对象中,该对象也就是简单工厂对象。
public class SimpleFactory {
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;
}
}
public class PizzaStoreSF {
SimpleFactory factory;
public PizzaStoreSF(SimpleFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
* 当有该商店需要添加或删除某比萨时,只需要往该类中createPizza方法添加对应的逻辑以及添加一个继承自Pizza类。这样也就实现对扩展开放,对修改封闭。当然如果从每次都要修改工厂类来说算是有些违背了开闭原则,但是如果对于逻辑不算复杂的工厂类来说还是可以接受的。
* 优点:所有的业务代码都集中在工厂类中,代码逻辑简单
* 缺点:当业务特别复杂后,该简单工厂类便难以维护,这里再次运用多态特性对该工厂进行抽取(也就是工厂方法模式)
运用了继承、封装、多态、接口等编程特性,以及对扩展开放,对修改封闭、基于接口编程而非实现编程等思想。
当创建具体对象的业务逻辑不太复杂,也就是可以容忍工厂类中有多个类似 if 分支的情况下可直接使用简单工厂模式(能容许工厂类在一定程度上不符合开闭原则);如果非要将这些if分支进行优化,或者是说当业务变得更加复杂后,则就需要引入工厂方法模式了。
定义了一个创建对象的接口,但是由子类决定实例化的类是哪一个,其将类的实例化推迟到子类。
从简单工厂类代码来说,当每添加都删除一个类型的比萨就得修改该代码,以及当添加的类型很多后,该代码也会变得很复杂。
因此要做的就是通过多态优化以下代码,个人感觉这有点像对简单工厂进行再一次简单工厂的处理。
优化的思路是,重新定义一个创建工厂超类(抽象或接口),该工厂超类定义了创建对应工厂的方法,然后各个比萨类型定义成工厂类(继承工厂超类并实现同样的创建工厂方法)。
示例代码如下:
public interface PizzaFactory {
Pizza createPizza(String type);
}
public class GreekPizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza(String type) {
// TODO Auto-generated method stub
return new GreekPizza();
}
}
注:其他所有比萨都类似继承自工厂超类并实现对应的创建比萨方法。
public class PizzaStore {
public Pizza orderPizza(String type) {
PizzaFactory factory = null;
if ("cheese".equals(type)) {
factory = new CheesePizzaFactory();
} else if ("greek".equals(type)) {
factory = new GreekPizzaFactory();
} else if ("pepperoni".equals(type)) {
factory = new PepperoniPizzaFactory();
}
Pizza pizza = factory.createPizza(type);
System.out.println("Pizza type class is " + pizza.getClass());
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
我们注意到上述代码似乎又回到了原先没有应用工厂方法前了,存在多个if分支,因此可对上述代码进行一定程度的优化,通过多态将if分支替换掉;
4. 简单工厂方法的优化版
创建存储比萨及其对应比萨工厂类的映射类,代码如下
public class PizzaFactoryMap {
private static final HashMap factoryCatch = new HashMap();
static {
factoryCatch.put("cheese", new CheesePizzaFactory());
factoryCatch.put("greek", new GreekPizzaFactory());
factoryCatch.put("pepperoni", new PepperoniPizzaFactory());
}
static PizzaFactory createFactory(String type) {
if (type.isEmpty() || type == null) {
return null;
}
return factoryCatch.get(type.toLowerCase());
}
}
public class PizzaStore2 {
public Pizza orderPizza(String type) {
PizzaFactory factory = PizzaFactoryMap.createFactory(type);
Pizza pizza = factory.createPizza(type);
System.out.println("Pizza type class is " + pizza.getClass());
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public static void main(String[] args) {
PizzaStore2 store = new PizzaStore2();
store.orderPizza("greek");
}
}
上述这些继承与实现其实最终主要是方便应用多态这一特性实现类把实例化推迟到子类。
下图引自Head First工厂方法的类图
优秀博客:简单工厂模式、工厂模式以及抽象工厂模式(具体)