工厂模式有简单工厂模式工厂方法模式和抽象工厂模式几种形态其中简单工厂模式和工厂方法模式已经在前面作过介绍在这里我们来介绍抽象工厂模式 抽象工厂模式是所有形态的工厂模式中最为抽象和最具广泛性的一种形态 抽象工厂模式的定义 抽象工厂模式是工厂方法模式的进一步扩广化和抽象化我们给出抽象工厂模式的类图定义如下 图 抽象工厂模式的类图定义 从上图可以看出简单工厂模式涉及到以下的角色 抽象工厂(AbstractFactory)类或接口 担任这个角色的是工厂方法模式的核心它是与应用程序无关的任何在模式中创立对象的工厂类必须实现这个接口或继承这个类 实工厂类 (Conrete Factory) 担任这个角色的是与应用程序紧密相关的直接在应用程序调用下创立产品实例的那样一些类 抽象产品 (Abstract Product) 担任这个角色的类是工厂方法模式所创立的对象的父类或它们共同拥有的接口 实产品 (Concrete Product) 担任这个角色的类是工厂方法模式所创立的任何对象所属的类 怎么这个类图和工厂方法模式的类图看起来是一样的? 是的图是一样的但是含义有很大的不同必须指出在抽象工厂模式中抽象产品 (AbstractProduct) 可能是一个或多个从而构成一个或多个产品族(Product Family) 在只有一个产品族的情况下抽象工厂模式实际上退化到工厂方法模式在上面的类图中只给出了一个产品族相当于位图中的一个点而完整的位图应当是三维的如下图 图 抽象工厂模式的位图 从位图可以清楚地看到与纸面垂直的数轴即第三维轴是代表产品族的数轴上面的位图中展示的是有两个产品族族A和族B的情形 在只有一个产品族时第三维就坍缩掉位图也就只剩下两维这时抽象工厂模式就退化得与工厂方法模式一模一样 在什么情形下应当使用抽象工厂模式 在以下情况下应当考虑使用抽象工厂模式 首先一个系统应当不依赖于产品类实例被创立组成和表示的细节这对于所有形态的工厂模式都是重要的 其次这个系统的产品有多于一个的产品族 第三同属于同一个产品族的产品是设计成在一起使用的这一约束必须得在系统的设计中体现出来 最后不同的产品以一系列的接口的面貌出现从而使系统不依赖于接口实现的细节 其中第二丶第三个条件是我们选用抽象工厂模式而非其它形态的工厂模式的关键性条件 抽象工厂模式在小花果园系统中的实现 现在我们在佛罗里达的渡假小屋修整好啦接下来一项重要而光荣的工作就是开发小屋后面的小花园这意味着我们有两处小花园需要照料一处在北方地区另一处在亚热带地区抽象工厂模式正好适用于我们的情况 图 抽象工厂模式应用于小花果园系统中三种不同的背景颜色可以区分工厂类蔬菜类(第一产品族)和水果类的类图(第二产品族) 两处花园就相当于两个产品族显然给北方花园的植物是要种植在一起的给南方花园的植物是要另种植在一起的这种分别应当体现在系统的设计上面这就满足了应当使用抽象工厂模式的第二和第三个条件 package comjavapatternsabstractfactory; public interface Gardener {} 代码清单 接口 Gardener package comjavapatternsabstractfactory; public class NorthenGardener implements Gardener { public VeggieIF createVeggie(String name) { return new NorthernVeggie(name); } public FruitIF createFruit(String name) { return new NorthernFruit(name); } } 代码清单 实工厂类 NorthenGardener package comjavapatternsabstractfactory; public class TropicalGardener implements Gardener { public VeggieIF createVeggie(String name) { return new TropicalVeggie(name); } public FruitIF createFruit(String name) { return new TopicalFruit(name); } } 代码清单 实工厂类 TropicalGardener package comjavapatternsabstractfactory; public interface VeggieIF {} 代码清单 接口 VeggieIF package comjavapatternsabstractfactory; public class NorthernVeggie implements VeggieIF { public NorthernVeggie(String name) { thisname = name; } public String getName(){ return name; } public void setName(String name){ thisname = name; } private String name; } 代码清单 实产品类 NorthernVeggie实产品类 NorthernFruit 与此极为类似故略去 package comjavapatternsabstractfactory; public class TropicalVeggie implements VeggieIF { public TropicalVeggie(String name) { thisname = name;} public String getName(){ return name; } public void setName(String name){ thisname = name; } private String name; } 代码清单 实产品类 TropicalVeggie实产品类 TropicalFruit 与此极为类似故略去 笔者对植物的了解有限为免遗笑大方在上面的系统里采用了简化处理没有给出高纬度和低纬度的水果类或蔬菜类的具体名称 抽象工厂模式的另一个例子 这个例子讲的是微型计算机的生产产品族有两个PC(IBM系列)和Mac(MacIntosh系列)显然我们应该使用抽象工厂模式而不是工厂方法模式因为后者适合于处理只有一个产品族的情形 图 抽象工厂模式应用于微型计算机生产系统中两种不同的背景颜色可以区分两类产品族及其对应的实工厂类 关于模式的实现 在抽象实现工厂模式时有下面一些值得注意的技巧 第一丶实工厂类可以设计成单态类很显然在小花果园系统中我们只需要 NorthenGardener 和TropicalGardener 的一个实例就可以了关于单态类的知识请见<爪哇语言单态类创立性模式> 第二丶在实现抽象工厂模式时产品类往往分属多于一个的产品族而针对每一族都需要一个实工厂类在很多情况下几个实工厂类都彼此相象只有些微的差别 这时笔者建议使用原始模型(Prototype)模式这一模式会在以后介绍届时作者会进一步阐述这一点 第三丶设计更加灵活的实工厂以微型计算机生产系统为例PCProducer 是一个实工厂类它的不灵活之处在于每一种产品都有一个工厂方法CPU 有createCPU()RAM 有createRAM()等等如果一个已有的系统需要扩充比如增加硬盘这一新产品我们就需要增加一系列的接口 (createHD())丶类(HD PCHD MacHD)和方法这似乎不很理想 一个解决的办法是把createCPU()createRAM() createHD()这几个方法合并为一个createPart(String type)方法这个合并后的方法返还一个Part接口所有的产品都要实现这一接口而CPURAM和HD接口则不再需要了每一个实产品都需要有一个属性表明它们的种类是CPURAM和HD 这样做的结果是数据类型的丰富结构被扁平化了客户端拿到的永远是一个Part接口这对客户端而言不很安全 第四丶抽象工厂类可以配备静态方法以返还实工厂设计的方法有两种 一种是以一个静态方法按照参量的值返回所对应的实工厂静态方法的数据类型是抽象方法类 另一种是以每一个实工厂类都配备一个静态方法其数据类型是该实工厂类 问答题 第题如上面的讨论抽象工厂类可以配备一个静态方法按照参量的值返回所对应的实工厂请把微型计算机生产系统的抽象工厂类按照这一方案改造给出UML类图和源代码 第题如上面的讨论抽象工厂类可以配备一系列静态方法对应一系列的实工厂请把微型计算机生产系统的抽象工厂类按照这一方案改造给出UML类图和源代码 第题如上面的讨论实工厂类可以设计成单态类请在第题的基础上把微型计算机生产系统的实工厂类按照这一方案改造给出UML类图和源代码 问答题答案 第题微型计算机生产系统的抽象工厂原本是接口现在需要改造成抽象类 图 三种不同的背景颜色可以区分抽象工厂类两类产品族及其对应的实工厂类ComputerProducer 类图中类名为斜体表明该类是抽象的而getProducer()的下划线表明该方法是静态的 package comjavapatternsabstractfactoryexercise; public class ComputerProducer { public static ComputerProducer getProducer(String which) { if (whichequalsIgnoreCase(PC)) { return new PCProducer(); } else (whichequalsIgnoreCase(Mac)) { return new MacProducer(); } } } 代码清单 抽象类 ComputerProducer 的方法 getProducer(String which) 第题略 第题本题答案是在第题基础之上的 |