正如同笔者在<简单工厂模式>一节里介绍的工厂模式有简单工厂模式工厂方法模式和抽象工厂模式几种形态简单工厂模式已经在前面作过介绍在简单工厂模式中一个工厂类处于对产品类实例化调用的中心位置上它决定那一个产品类应当被实例化 如同一个交通警察站在来往的车辆流中决定放行那一个方向的车辆向那一个方向流动一样 而本节要讨论的工厂方法模式是简单工厂模式的进一步抽象化和推广它比简单工厂模式聪明的地方在于 它不再作为一个具体的交通警察的面貌出现而是以交通警察局的面貌出现它把具体的车辆交通交给下面去管理换言之工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化这个决定被交给子类去作处于工厂方法模式的中心位置上的类甚至都不去接触那一个产品类应当被实例化这种细节这种进一步抽象化的结果是这种新的模式可以用来处理更加复杂的情形 为什么需要工厂方法模式 现在让我们继续考察我们的小花果园在<简单工厂模式>一节里我们在后花园里引进了水果类植物 构造了简单工厂模式来处理 使用一个FruitGardener类来负责创立水果类的实例见下图 图 简单工厂模式FruitGardener掌握所有水果类的生杀大权 在这一节里我们准备再次引进蔬菜类植物比如 西红柿 (Tomato) 土豆 (Potato) 西芥兰花 (Broccoli) 蔬菜与花和水果当然有共同点可又有不同之处蔬菜需要喷洒(dust)杀虫剂(pesticide)除虫 不同的蔬菜需要喷洒不同的杀虫剂等等怎么办呢? 那么再借用一下简单工厂模式不就行了? 再设计一个专管蔬菜类植物的工厂类比如 图 简单工厂模式VeggieGardener掌握所有蔬菜类的生杀大权 这样做一个明显的不足点就是不够一般化和抽象化在FruitGardener和VeggieGardener类之间明显存在很多共同点 这些共同点应当抽出来一般化和框架化这样一来如果后花园的主人决定再在园子里引进些树木类植物时 我们有框架化的处理方法本节所要引入的工厂方法模式就符合这样的要求 简单工厂模式的回顾 有必要首先回顾一下简单工厂模式的定义以便于比较 图 简单工厂模式的类图定义 从上图可以看出简单工厂模式涉及到以下的角色 工厂类 (Creator) 担任这个角色的是工厂方法模式的核心是与应用程序紧密相关的直接在应用程序调用下创立产品实例的那个类工厂类只有一个而且是实的见下面的位图 产品 (Product) 担任这个角色的类是工厂方法模式所创立的对象的父类或它们共同拥有的接口 实产品 (Concrete Product) 担任这个角色的类是工厂方法模式所创立的任何对象所属的类 实产品类可以是分布在一维数轴上的分立点 中的任何一个见下面的位图 工厂方法模式的定义 我们给出工厂方法模式的类图定义如下 图 工厂方法模式的类图定义 从上图可以看出工厂方法模式涉及到以下的角色 抽象工厂接口(Creator) 担任这个角色的是工厂方法模式的核心它是与应用程序无关的任何在模式中创立对象的工厂类必须实现这个接口 实工厂类 (Conrete Creator) 担任这个角色的是与应用程序紧密相关的直接在应用程序调用下创立产品实例的那样一些类 实工厂类可以是分布在一维数轴上的分立点 中的任何一个见下面的位图 产品 (Product) 担任这个角色的类是工厂方法模式所创立的对象的父类或它们共同拥有的接口 实产品 (Concrete Product) 担任这个角色的类是工厂方法模式所创立的任何对象所属的类 实产品类可以是分布在二维平面上的分立点 () () ()中的任何一个见下面的位图 由实工厂(横数轴上第一点)创立的对象来自实产品类() () ()由实工厂(横数轴上第二点)创立的对象来自实产品类() () ()依此类推 工厂方法模式和简单工厂模式在定义上的不同是很明显的工厂方法模式的核心是一个抽象工厂类而不像简单工厂模式 把核心放在一个实类上工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来 从而可以在实际上成为多个简单工厂模式的综合从而推广了简单工厂模式 反过来讲简单工厂模式是由工厂方法模式退化而来设想如果我们非常确定一个系统只需要一个实的工厂类 那么就不妨把抽象工厂类合并到实的工厂类中去而这样一来我们就退化到简单工厂模式了 与简单工厂模式中的情形一样的是ConcreteCreator 的factory() 方法返还的数据类型是一个接口 PlantIF而不是哪一个具体的产品类这种设计使得工厂类创立哪一个产品类的实例细节完全封装在工厂类内部 工厂方法模式又叫多形性工厂模式显然是因为实工厂类都有共同的接口或者都有共同的抽象父类 工厂方法模式在小花果园系统中的实现 好了现在让我们回到小花果园的系统里看一看怎样发挥工厂方法模式的威力解决需要接连不断向小花果园引进不同类别的植物所带来的问题 首先我们需要一个抽象工厂类比如叫做 Gardener作为两个实工厂类 FruitGardener 及 VeggieGardener 的父类 Gardener 的 factory() 方法可以是抽象的留给子类去实现也可以是实的在父类实现一部分功能再在子类实现剩余的功能我们选择将 factory() 做成抽象的主要是因为我们的系统是一个示范系统内容十分简单没有要在父类实现的任何功能 图 工厂方法模式在小花果园系统中的实现 抽象工厂类 Gardener 是工厂方法模式的核心但是它并不掌握水果类或蔬菜类的生杀大权相反地这项权力被交给子类即 VeggieGardener 及 FruitGardener package comjavapatternsfactorymethod; abstract public class Gardener { public abstract PlantIF factory(String which) throws BadFruitException; } 代码清单 父类 Gardener package comjavapatternsfactorymethod; public class VeggieGardener extends Gardener { public PlantIF factory(String which) throws BadPlantException { if (whichequalsIgnoreCase(tomato)) { return new Tomato(); } else if (whichequalsIgnoreCase(potato)) { return new Potato(); } else if (whichequalsIgnoreCase(broccoli)) { return new Broccoli(); } else { throw new BadPlantException(Bad veggie request); } } } 代码清单 子类 VeggieGardener package comjavapatternsfactorymethod; public class FruitGardener extends Gardener { public PlantIF factory(String which) { if (whichequalsIgnoreCase(apple)) { return new Apple(); } else if (whichequalsIgnoreCase(strawberry)) { return new Strawberry(); } else if (whichequalsIgnoreCase(grape)) { return new Grape(); } else { throw new BadPlantException(Bad fruit request); } } } 代码清单 子类 FruitGardener package comjavapatternsfactorymethod; public class Broccoli implements VeggieIF PlantIF { public void grow() { log(Broccoli is growing); } public void harvest() { log(Broccoli has been harvested); } public void plant() { log(Broccoli has been planted); } private static void log(String msg) { Systemoutprintln(msg); } public void pesticideDust(){ } } 代码清单 蔬菜类 Broccoli其它的蔬菜类与 Broccoli 相似因此不再赘述 package comjavapatternsfactorymethod; public class Apple implements FruitIF PlantIF { public void grow() { log(Apple is growing); } public void harvest() { log(Apple has been harvested); } public void plant() { log(Apple has been planted); } |