1、抽象工厂接口,用来派生具体工厂类,它对外提供了统一的获取产品的方法名。
2、具体工厂类,继承/派生自抽象工厂接口,由具体工厂类实现具体产品的创建。
3、抽象产品接口,用来派生具体的产品,它规范了所有产品的统一类型,保证客户端得到的产品超类型的一致。
4、具体产品类,继承/派生自抽象产品接口。特别要注意的是,这些具体产品仍属于同一个产品树,举个例子:如果鞋子是抽象产品类的话,那么皮鞋、运行鞋就是具体的产品。
/** *抽象工厂方法接口 */ interface FactoryMethod{ /** *统一生成产品的方法 */ public function createProduct(); } /** *生产产品A的具体工厂方法A */ class ConcreteFactoryA implements FactoryMethod{ /** *实现接口 */ public function createProduct(){ return new ConcreteProductA(); } } /** *生产产品B的具体工厂方法B */ class ConcreteFactoryB implements FactoryMethod{ /** *实现接口 */ public function createProduct(){ return new ConcreteProductB(); } } /** *抽象产品接口 */ interface Product{ public function show(); } /** *产品A */ class ConcreteProductA implements Product{ /** *实现接口方法 */ public function show(){ echo 'This is product A<br>'; } } /** *产品B */ class ConcreteProductB implements Product{ /** *实现接口方法 */ public function show(){ echo 'This is product B<br>'; } } //A工厂负责生产A产品 $concreteFactoryA = new ConcreteFactoryA(); $product = $concreteFactoryA->createProduct(); $product->show(); //B工厂负责生产B产品 $concreteFactoryB = new ConcreteFactoryB(); $product = $concreteFactoryB->createProduct(); $product->show();简单工厂模式违背了对修改关闭的原则,当需要增加新的产品,必须去修改简单工厂类的内部代码(增加条件判断),从而要重新编绎这个类。
工厂方法模式有效地克服了简单工厂的缺点,当要增加新的产品时,只需要增加一个对应的具体工厂类就好了(对扩展开放原则)。但是缺点也是很明显的,每增加一个产品就得对应增加一个工厂类,如果产品种类多的话,那么工厂类的数量也相应增多。
《Head First Pattern》中披萨店生产披萨的示例:
abstract class PizzaStore{ public function orderPizza(){ $pizza = $this->createPizza();//将稳定的部分封装在抽象类里面 $pizza->prepare(); $pizza->bake(); $pizza->cut(); $pizza->box(); return $pizza; } abstract public function createPizza(); //实例化产品类推迟到子类去实现。 } class NYPizzaStore extends PizzaStore{ public function createPizza(){ return new NYPizza(); } } class WDCPizzaStore extends PizzaStore{ public function createPizza(){ return new WDCPizza(); } } abstract class Pizza{ abstract public function prepare(); abstract public function bake(); abstract public function cut(); abstract public function box(); } class NYPizza extends Pizza{ public function prepare(){ echo 'NYPizza is preparing<br>'; } public function bake(){ echo 'NYPizza is baking<br>'; } public function cut(){ echo 'NYPizza is cutting<br>'; } public function box(){ echo 'NYPizza is boxing<br>'; } } class WDCPizza extends Pizza{ public function prepare(){ echo 'WDCPizza is preparing<br>'; } public function bake(){ echo 'WDCPizza is baking<br>'; } public function cut(){ echo 'WDCPizza is cutting<br>'; } public function box(){ echo 'WDCPizza is boxing<br>'; } } $pizzaStore = new NYPizzaStore(); $pizza = $pizzaStore->orderPizza(); $pizzaStore = new WDCPizzaStore(); $pizza = $pizzaStore->orderPizza();