老子有钱下载官网
  咨询电话:15395592738

老子有钱88APP

抽象工厂模式

2018年8月24日17:20:30

抽象工厂模式

定义

借我一只晨光的铅笔,明天就还给你。

现在我可以还你晨光的铅笔了,你早已不在了,明天还是明天。

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。——《设计模式:可复用面向对象软件的基础》

使用场景

首先要来认识两个新概念:产品族产品等级结构

产品族,是指不同产品等级结构中,功能相关的产品组成的家族。

产品等级结构, 即产品的继承结构,继承(或实现)同一抽象产品的具体产品属于同一产品等级结构。

在后面的代码示例中,晨光文具和真彩文具是两个产品族,继承(或实现)铅笔抽象产品的晨光铅笔和真彩铅笔是一个产品等级结构,继承(或实现)橡皮抽象产品的晨光铅笔和真彩铅笔是另一个产品等级结构。【这个我用了继承(或实现)是因为Java中有接口是实现的,抽象类是继承的,抽象产品既可以是接口,也可以是抽象类,为了不误导我自己,特意加上。】例子还有:Intel的主板、芯片组、CPU是一个产品族,AMD的主板、芯片组、CPU也是一个产品族,而这里有三个产品等级结构,分别是:主板、芯片组、CPU。

想代码示例的时候,想我们经常用的东西,就想到了文具,想到了晨光和真彩。查了一下,没想到小小文具,营业额超十亿。

现在我们的目标是先赚他一个亿,开一家博客园文具(产品族),产品等级结构呢,他们都有,我们直接继承(或实现)他们的抽象产品类就好了,多方便。这就是抽象工厂模式的好处。增加一个产品族,不用破坏原来代码结构,符合开闭原则。

但是只有老产品,没有什么竞争力,要不我们增加一个新产品即新的产品等级结构,暂时就是码农作弊专用智能笔,帮你轻松应对笔试,这时我们就要在博客园文具(产品族)添加新成员,需要在博客园文具具体工厂类中添加相关创建新产品的代码,不符合开闭原则。这就是抽象工厂模式的缺点了。

综上所述,结合其他情况,以下情况可以使用抽象工厂模式:

1、一个系统不应当依赖于产品实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。

2、系统有多于一个的产品,且每次只使用其中一个产品族。

3、属于同一产品族的产品将在一起使用,这一约束应该在系统设计中体现出来。

4、所有产品以自己继承(或实现)的接口出现,从而客户端不依赖于具体实现。

第1点,毋庸置疑。第2点和第3点,说的是我选择晨光文具,我使用的就是晨光的铅笔就要使用晨光的橡皮,要配套使用,不能是我使用了晨光的铅笔却使用真彩的橡皮。这个约束在这个例子看起来有点牵强,但是想一下这样的场景:期末考试要同一文具,有两种选择,一种是晨光,一种是真彩,他们是配套的,晨光的铅笔配晨光的橡皮,真彩的铅笔配真彩的橡皮,这样就舒服了。第4点,面向接口编程,降低耦合。

第2点和第3点,用上面提到的Intel、AMD产品族更贴切,Intel的CPU是无法和AMD的主板匹配的,AMD的CPU也无法和Intel的主板匹配,所以组装电脑的时候,就默认有这个约束:只能使用同一个产品族中的产品。

关于抽象工厂模式的起源,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。视窗构建时,只能选择一个操作系统的Button和Text,如果不是,两个操作系统都用不了,我要这视窗有何用?

角色

抽象工厂角色(Abstract Factory):具体工厂(产品族)公共接口

具体工厂角色(Concrete Factory):产品族

抽象产品角色(Abstract Product):产品等级结构

具体产品角色(Concrete Product):产品

图示

代码示例

代码示例类依赖关系图:

抽象工厂角色(AbstractFactory.java)

public interface AbstractFactory { public Pencil createPencil(); public Eraser createEraser();}

具体工厂角色(ChenGuangFactory.java、TrueColorFactory.java)

// 晨光工厂public class ChenGuangFactory implements AbstractFactory { @Override public Pencil createPencil() { return new ChenGuangPencil(); } @Override public Eraser createEraser() { return new ChenGuangEraser(); }}// 真彩工厂public class TrueColorFactory implements AbstractFactory{ @Override public Pencil createPencil() { return new TrueColorPencil(); } @Override public Eraser createEraser() { return new TrueColorEraser(); }}

抽象产品角色(Pencil.java、Eraser.java)

// 铅笔public interface Pencil { public void draw();}// 橡皮public interface Eraser { public void erase();}

具体产品角色(ChenGuangPencil.java、TrueColorPencil.java、ChenGuangEraser.java、TrueColorEraser.java)

// 晨光铅笔public class ChenGuangPencil implements Pencil { @Override public void draw() { System.out.println("用晨光铅笔画图。"); }}// 真彩铅笔public class TrueColorPencil implements Pencil { @Override public void draw() { System.out.println("用真彩铅笔画图。"); }}// 晨光橡皮public class ChenGuangEraser implements Eraser { @Override public void erase() { System.out.println("用晨光橡皮擦除晨光铅笔画的图。"); }}// 真彩橡皮public class TrueColorEraser implements Eraser { @Override public void erase() { System.out.println("用真彩橡皮擦除真彩铅笔画的图。"); }}

测试类(AbstractFactoryTest.java)

public class AbstractFactoryTest { public static void main(String[] args) { // 1、晨光 AbstractFactory factory = new ChenGuangFactory(); Pencil pencil = factory.createPencil(); pencil.draw(); // 用晨光铅笔画图。 Eraser eraser = factory.createEraser(); eraser.erase(); // 用晨光橡皮擦除晨光铅笔画的图。 // 2、真彩 AbstractFactory factoryT = new TrueColorFactory(); Pencil pencilT = factoryT.createPencil(); pencilT.draw(); // 用真彩铅笔画图。 Eraser eraserT = factoryT.createEraser(); eraserT.erase(); // 用真彩橡皮擦除真彩铅笔画的图。 }}

测试结果:

优点

1、拥有简单工厂模式、工厂方法模式一样的优点:客户端不需要知道对象被创建的细节

2、当产品族中多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的产品。

3、增加产品族,符合开闭原则。

缺点

1、增加产品等级结构时,不符合开闭原则。

总结

抽象工厂模式在工厂方法模式的基础上,增添了产品族产品等级结构的概念,以及只使用同一个产品族中的约束,使得抽象工厂模式符合现实生活中的某些场景,成为实用的设计模式,再加上抽象工厂模式实现高内聚低耦合,也为其广泛应用提供基础。

(给晨光和真彩做广告,是不是应该收点广告费???)

参考:

《JAVA与模式》之抽象工厂模式

2018年8月25日18:31:58