工厂方法模式定义:Define an interface for creating an object,but let subclass decide which class to instantiate.Factory Methode lets a class defer instantiate to subclass.工厂方法模式定义了一个创建方法的接口,但由子类决定要初始化的类是哪一个,工厂方法让类把实例化推迟到子类。
两家PizzaStore,NYPizzaStore提供纽约风味的pizza,CHPizzaStore提供芝加哥风味的pizza:
public abstract class PizzaStore { public abstract Pizza orderPizza(String type);}
public class NYPizzaStore extends PizzaStore { private NYPizzaFactory factory; public NYPizzaStore(NYPizzaFactory factory){ this.factory = factory; } public Pizza orderPizza(String type) { Pizza pizza = factory.createPizza(type); pizza.prepare(); return pizza; }}
public class CHPizzaStore extends PizzaStore { private CHPizzaFactory factory; public CHPizzaStore(CHPizzaFactory factory){ this.factory = factory; } public Pizza orderPizza(String type) { Pizza pizza = factory.createPizza(type); pizza.prepare(); pizza.cut(); return pizza; }}
public class NYPizzaFactory{ public Pizza createPizza(String type) { Pizza pizza = null; if(type == "cheese"){ pizza = new NYCheessePizza(); }else if(type == "greek"){ pizza = new NYGreekPizza(); } return pizza; }}
public class CHPizzaFactory{ public Pizza createPizza(String type) { Pizza pizza = null; if(type == "cheese"){ pizza = new CHCheessePizza(); }else if(type == "greek"){ pizza = new CHGreekPizza(); } return pizza; }}
public abstract class Pizza { public abstract void prepare(); public abstract void cut();}
public class CHCheessePizza extends Pizza { public void prepare() { System.out.println("CHCheesePizza prepare!"); } public void cut() { System.out.println("CHCheesePizza cut!"); }}
其它的pizza是一样的,测试一下:
public class Test { public static void main(String[] args) { NYPizzaFactory nyfactory = new NYPizzaFactory(); NYPizzaStore nystore = new NYPizzaStore(nyfactory); nystore.orderPizza("cheese"); CHPizzaFactory chfactory = new CHPizzaFactory(); CHPizzaStore chstore = new CHPizzaStore(chfactory); chstore.orderPizza("greek"); }}
NYCheessePizza prepare!CHGreekPizza prepare!CHGreekPizza cut!
PizzaStore是一个抽象的接口,那么继承类通过重写其orderPizza()方法可以自由的实现各自的流程
比如NYPizzaStore的pizza在送出前是不需要cut()的,但是CHPizzaStore的pizza在送出前需要cut(),能不能使NYPizzaStore和CHPizzaStore都保持相同的工作流程,在送出pizza的时候强制要求先进行prepare()然后再进行cut()呢?
由于使用了PizzaStore抽象类,那么使继承类具有相同行为的方式显然是将该行为抽象至他们共同的父类中,并禁止该行为的重写
public abstract class PizzaStore { public final Pizza orderPizza(String type){ Pizza pizza = ? pizza.prepare(); pizza.cut(); return pizza; };}
如此便可保证所有的Pizza在送出前先必须先进行prepare()然后进行cut()
(最初的目的是希望将共同的部分提取出来,以提高代码的复用性,手段是将共同的代码提炼至抽象父类,结果是导致了所有的继承类都必须具有相同的流程,算是有利有弊)
但关键问题是,如何初始化Pizza,在PizzaStore中,根本就不知道将要调用orderPizza方法的是CHPizzaStore类还是NYPizzaStore类,因此没法判断应该提供何种特定类型的pizza(比如:CHCheesePizza)
但是继承类知道自己需要何种类型的Pizza(NYPizzaStore当然知道自己需要NYCheesePizza),那么就让继承类自己创建所需的Pizza好了,这就是工厂方法模式
NYPizzaStore中的createPizza()方法和前面的NYPizzaFactory类的作用是一样的,区别只是将createPizza()放在继承类中,而没有抽象为一个具体的简单工厂类型
工厂方法这个名字很贴切
public abstract class PizzaStore { public abstract Pizza createPizza(String type); public final Pizza orderPizza(String type) { Pizza pizza = this.createPizza(type); pizza.prepare(); pizza.cut(); return pizza; }}
public class NYPizzaStore extends PizzaStore{ public Pizza createPizza(String type) { Pizza pizza = null; if(type == "cheese"){ pizza = new NYCheessePizza(); }else if(type == "greek"){ pizza = new NYGreekPizza(); } return pizza; }}
public class CHPizzaStore extends PizzaStore { public Pizza createPizza(String type) { Pizza pizza = null; if(type == "cheese"){ pizza = new CHCheessePizza(); }else if(type == "greek"){ pizza = new CHGreekPizza(); } return pizza; }}
我知道有一个pizza,但并不知道pizza的具体类型,store没有和特定的pizza类型耦合:
public class Test { public static void main(String[] args) { PizzaStore store = new NYPizzaStore(); Pizza pizza = store.orderPizza("cheese"); store = new CHPizzaStore(); pizza = store.orderPizza("greek"); }}
NYCheessePizza prepare!NYCheessePizza cut!CHGreekPizza prepare!CHGreekPizza cut!
高层组件PizzaStore和底层组件Pizza实现类都依赖抽象类Pizza,真正的松耦合设计
这样就可以看出工厂方法模式的功能了,既能提供一个框架保证所有的继承类都能按照我的流程来,又没有特定类之间的耦合