一个例子 : 某公司生产 Android 手机。
分析 : 由上一篇工厂方法模式分析其中的角色和结构
抽象产品角色 : Android Mobile
具体产品角色 : SAMSUNG Android Mobile, HTC Android Mobile, 等等...
抽象工厂角色 : MobileFactory
具体工厂角色 : SAMSUNGFactory,HTCFactory,等等...
类图如下 :
package com.ds.factory; // 抽象产品类 public abstract class AndroidMobile { public abstract void call(); }
package com.ds.factory; // 具体产品类 public class SAMAndroidMobile extends AndroidMobile { @Override public void call() { System.out.println("this is SAMSUNG Mobile's call method"); } }
package com.ds.factory; //具体产品类 public class HTCAndroidMobile extends AndroidMobile { @Override public void call() { System.out.println("this is HTC Mobile's call method"); } }
以上具体产品是可以有多个的, 例子只写了两个。
下面是工厂类等级结构代码 :
package com.ds.factory; //抽象工厂类 什么时候用抽象类什么时候用接口在上一篇已经描述过。 public abstract class MobileFactory { public abstract AndroidMobile createAndroidMobile(); }
package com.ds.factory; // SAMSUNG 工厂类 public class SAMFactory extends MobileFactory{ @Override public AndroidMobile createAndroidMobile() { return new SAMAndroidMobile(); } }
package com.ds.factory; //具体产品类 public class HTCAndroidMobile extends AndroidMobile { @Override public void call() { System.out.println("this is HTC Mobile's call method"); } }
客户端代码:
package com.ds.factory; public class Client { public static void main(String[] args) { MobileFactory factory = new SAMFactory(); //一般在项目中具体的工厂是通过配置注入进来的。而且项目中变化的往往是产品而不是工厂。 factory.createAndroidMobile().call(); factory = new HTCFactory(); // 客户端只需获取工厂就可以根据不同的工厂获取不同的产品。产品的创建过程和细节对于客户端而言是不需要知道的。 factory.createAndroidMobile().call(); } }
在软件的世界里,唯一不变的是变化。
如果有新的产品的出现,比如说 Windows 系统的手机, IOS 系统的手机。如果采用工厂方法模式,那么每加入一个产品,就要建立相应的工厂。每一个产品等级结构需要有相应的工厂等级结构。 这样会使得工厂类增多而变得复杂。
如下图 :
可以看出, 每次新增一个产品等级结构,就要相应的增加一个工厂的等级结构。
改进:
可以把HTC的Android和Windows,SAM的Android和Windows看做一个产品族,从上图看出Windows 的具体产品,具体工厂和Android的具体产品,具体工厂有相同的品牌。
改进后的代码
package com.ds.factory; // 抽象产品类 新增WindowsMobile public abstract class WindowsMobile { public abstract void call(); }
package com.ds.factory; //具体产品类 HTCWindowsMobile 继承 WindowsMobile 新增的 HTC Windows Mobile public class HTCWindowsMobile extends WindowsMobile { @Override public void call() { System.out.println("this is HTC Windows Mobile's call method"); } }
package com.ds.factory; //具体产品类 SAMWindowsMobile 继承 WindowsMobil 新增的 SAM Windows Mobile public class SAMWindowsMobile extends WindowsMobile { @Override public void call() { System.out.println("this is SAMSUNG Windows Mobile's call method"); } }
改进后的工厂类(这里可以看出抽象工厂的一个缺陷,在新增产品等级结构的时候,工厂类的上层接口是要改变的,这是违背开闭原则的)
package com.ds.factory; //抽象工厂类 public abstract class MobileFactory { public abstract AndroidMobile createAndroidMobile(); //新增一个产品 WindowsMobile (这里可以看出抽象工厂的一个缺陷,在新增产品等级结构的时候,工厂类的上层接口是要改变的,这是违背开闭原则的) public abstract WindowsMobile createWindowsMobile(); }
package com.ds.factory; // HTC 工厂类 public class HTCFactory extends MobileFactory{ @Override public AndroidMobile createAndroidMobile() { return new HTCAndroidMobile(); } @Override //改进后的 HTC 工厂类 增加了一个 createWindowsMobile() public WindowsMobile createWindowsMobile() { return new HTCWindowsMobile(); } }
package com.ds.factory; // SAMSUNG 工厂类 public class SAMFactory extends MobileFactory{ @Override public AndroidMobile createAndroidMobile() { return new SAMAndroidMobile(); } @Override //改进后的 SAMSUNG 工厂类 增加了一个 createWindowsMobile() public WindowsMobile createWindowsMobile() { return new SAMWindowsMobile(); } }
客户端代码:
package com.ds.factory; public class Client { public static void main(String[] args) { MobileFactory factory = new SAMFactory(); //一般在项目中具体的工厂是通过配置注入进来的。而且项目中变化的往往是产品而不是工厂。 factory.createAndroidMobile().call(); factory.createWindowsMobile().call();
factory = new HTCFactory(); // 客户端只需获取工厂就可以根据不同的工厂获取不同的产品。产品的创建过程和细节对于客户端而言是不需要知道的。 factory.createAndroidMobile().call(); factory.createWindowsMobile().call(); // 客户端只增加了两行代码,可以看出对于产品的各种变化,客户端原有的代码是不受影响的。 } }
抽象工厂模式定义:
抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。
抽象工厂模式就是为解决工厂方法模式在面对有多个产品等级结构的问题而生的。
产品族和产品等级结构
产品族指的是位于不同产品等级结构中,功能相关联的的产品组成的家族。(如上, HTCAndroidMobile 和 HTCWindowsMobile 它们是不在同一产品等级结构的,但是它们具有相关联的地方,就是有同一品牌)
产品等级结构,指的是同一种类型的产品等级。
抽象工厂模式的结构和角色
角色和工厂方法模式是一样的,这里不再描述。
系统代码 :
package com.ds.factory.std; public interface ProductA { public void operation(); }
package com.ds.factory.std; public interface ProductB { public void operation(); }
package com.ds.factory.std; public class ProductA1 implements ProductA { @Override public void operation() { System.out.println(" this is ProductA1's operation method"); } }
package com.ds.factory.std; public class ProductA2 implements ProductA { @Override public void operation() { System.out.println(" this is ProductA2's operation method"); } }
package com.ds.factory.std; public class ProductB1 implements ProductB { @Override public void operation() { System.out.println(" this is ProductB1's operation method"); } }
package com.ds.factory.std; public class ProductB2 implements ProductB { @Override public void operation() { System.out.println(" this is ProductB2's operation method"); } }
package com.ds.factory.std; public interface Factory { public ProductA createProductA(); public ProductB createProductB(); }
package com.ds.factory.std; public class ConcreteFactory1 implements Factory { @Override public ProductA createProductA() { return new ProductA1(); } @Override public ProductB createProductB() { return new ProductB1(); } }
package com.ds.factory.std; public class ConcreteFactory2 implements Factory { @Override public ProductA createProductA() { return new ProductA2(); } @Override public ProductB createProductB() { return new ProductB2(); } }
什么时候使用抽象工厂模式
一个系统不依赖于产品类实例如何被创建,组合和表达的细节。
这个系统的产品有多于一个的产品族 (多个产品族,必然有多个产品等级结构)。
新增产品族 :
在产品等级结构的数目不变的情况下,增加新的产品族,就意味着每一个产品等级结构中增加一个(或多个)新的产品角色。(如 增加一个 HW的Android,Windows手机)。
只需要在系统中增加新的具体工厂类,和新的具体产品类。不需要修改已有的工厂角色和产品角色。
在新增产品族上,抽象工厂模式是支持"开闭原则"的。
新增产品等级结构 :
上面已经描述, 因为新增产品等级结构意味着要修改上层的工厂接口。每一个工厂角色都要修改。这显然是违背" 开闭原则"的。
工厂模式结束了。这篇博客写的真的是火大,第一次写了一小半,用Google查了一篇资料,浏览器崩溃了,没保存。第二次写了一半多了,图也截上去了,网络断了,然后浏览器又奔溃,又没保存!!!, 直接倒下睡觉 烦躁。
用PowerDesigner 画图时,那个Dependency的线总是拖不成功,然后乱点乱点把工具栏隐藏了,找了一晚上,最后如果没有Google我可能要疯了。
Anyway 总算写好了, 收获还是有的,练耐心,哈哈。工具使用熟悉多了。
痛苦过后的感觉很爽。敲代码的感觉也是非常cool的。