之前我们介绍了Factory Pattern工厂模式,其较适合于只有一种类型产品的场景。但有些时候一家工厂可能会生产多种类型的产品。比如家电厂无论海尔还是美的,都会生产冰箱、洗衣机、空调等多种不同类型的产品。这个时候,就可以应用我们这里所说的Abstract Factory Pattern抽象工厂模式
简介
这里我们以PC厂商为例来进入引入介绍。对于Dell、HP这些PC厂商而言,其会去生产销售显示器、鼠标、键盘等这些外设。换句话说,在这里,一家工厂将不再是只提供一种产品了,而是会去提供多种产品。所以对于Abstract Factory Pattern抽象工厂模式而言,其和Factory Pattern工厂模式相比,最大的不同就在于抽象工厂角色和具体工厂角色部分。这里我们先来简单介绍下Abstract Factory Pattern抽象工厂模式下的角色
- 抽象产品角色:其定义了具体产品的实现类所具有的共有方法,一般通过接口实现。本文中即为Monitor、Keyboard、Mouse接口类。它们分别定义了各自产品的公共特性
- 具体产品角色:其是抽象产品角色的具体实现类,即是客户真正需要的产品。这里即为不同PC厂家所提供的外设产品
- 抽象工厂角色:其定义了不同PC厂商的工厂的通用接口,用以提供该PC厂商所生产的各种不同种类的产品。故这也是其于Factory Pattern工厂模式最大的区别之处,后者(工厂模式)只提供一种类型的产品
- 具体工厂角色:其是抽象工厂的具体实现类,一个具体的工厂类负责提供其生产多种类型的产品
实践
现在让我们利用上文所提到的不同PC厂商(Dell、HP)的多种外设产品(键盘、显示器、鼠标)为例,通过代码进行地具体演示。相信大家对于抽象产品角色、具体产品角色的设计应该是比较熟悉的了。这里我们先给出显示器的接口及具体实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public interface Monitor { void display(); } ...
public class HpMonitor implements Monitor { @Override public void display() { System.out.println("HP 显示器正在显示"); } } ...
public class DellMonitor implements Monitor { @Override public void display() { System.out.println("DELL 显示器正在显示"); } }
|
对于键盘、鼠标产品而言,同理如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
public interface Keyboard { void use(); } ...
public class HpKeyboard implements Keyboard { @Override public void use() { System.out.println("HP 键盘正在使用"); } } ...
public class DellKeyboard implements Keyboard { @Override public void use() { System.out.println("DELL 键盘正在使用"); } }
public interface Mouse { void move(); } ...
public class HpMouse implements Mouse { @Override public void move() { System.out.println("HP 鼠标正在移动"); } } ...
public class DellMouse implements Mouse { @Override public void move() { System.out.println("DELL 鼠标正在移动"); } }
|
现在我们来定义一个抽象工厂角色——即PC厂商的接口类PCFactory,其可以提供各种不同类型产品
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public interface PCFactory {
Monitor getMonitor();
Mouse getMouse();
Keyboard getKeyboard(); }
|
有了抽象工厂角色,那么具体的工厂角色就简单了。本文就是Dell、HP的工厂类DellFactory、HpFactory,Client通过各自PC厂商的工厂类就可以获取相应的产品了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public class DellFactory implements PCFactory{ @Override public Monitor getMonitor() { return new DellMonitor(); }
@Override public Mouse getMouse() { return new DellMouse(); }
@Override public Keyboard getKeyboard() { return new DellKeyboard(); } } ...
public class HpFactory implements PCFactory{ @Override public Monitor getMonitor() { return new HpMonitor(); }
@Override public Mouse getMouse() { return new HpMouse(); }
@Override public Keyboard getKeyboard() { return new HpKeyboard(); } }
|
至此我们的抽象工厂模式就已经实现完毕了,那么现在就通过一个测试用例来看看是否可以正常工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class AbstractFactoryPatternDemo { public static void main(String[] args) { System.out.println("--------- Test 1 ---------"); PCFactory hpFactory = new HpFactory(); Monitor monitor = hpFactory.getMonitor(); Mouse mouse = hpFactory.getMouse(); Keyboard keyboard = hpFactory.getKeyboard(); monitor.display(); mouse.move(); keyboard.use();
System.out.println("--------- Test 2 ---------"); PCFactory dellFactory = new DellFactory(); monitor = dellFactory.getMonitor(); mouse = dellFactory.getMouse(); keyboard = dellFactory.getKeyboard(); monitor.display(); mouse.move(); keyboard.use(); } }
|
测试结果如下符合我们的预期
开闭原则的倾斜性
开闭原则是指对扩展开放、对修改封闭,通过扩展的方式来实现功能的增强。而在Abstract Factory Pattern抽象工厂模式下,如果我们期望在本文例子中再增加一个PC厂商Apple,那么就只需要添加苹果的工厂类及相关产品类即可,即此种功能拓展是符合开闭原则的;但如果是期望增加一种新的外设产品,比如光驱,那么我们不仅需要添加相关的产品类,更重要的是我们还需要在现有的工厂类(包括抽象工厂角色和具体工厂角色)中添加getCdDriver()方法,而这种功能拓展显然就违背了开闭原则。综上所述,在Abstract Factory Pattern抽象工厂模式中开闭原则是有倾斜性的
参考文献
- Head First 设计模式 弗里曼著