【一朝,王母娘娘设宴,大开宝阁,瑶池中做蟠桃胜会】

有一天,王母娘娘要在瑶池办party,就需要准备大量的食材。要知道,天上的神仙也分三六九等,九曜星、五方将、二十八宿、四大天王、十二元辰、五方五老、普天星相、河汉群神等等,不同等级的神仙在宴会中吃的东西也不一样。

为了方便管理,我们把神仙分为低级神仙、中级神仙和高级神仙,不同等级的神仙将领取到对应等级的食物,所以就有了低级神仙食物、中级神仙食物和高级神仙食物。

在前面的悟空模式-java-普通工厂模式悟空模式-java-工厂方法模式中都介绍了低级蟠桃(三千年)、中级蟠桃(六千年)和高级蟠桃(九千年),虽然是蟠桃盛会,但也总不能光吃蟠桃,所以由兜率宫拿出了一批仙丹,分为低级仙丹(炼三三得九天)、中级仙丹(炼七七四十九天)和高级仙丹(炼九九八十一天)。

以上,就是我们本次演示抽象工厂模式所需要的产品元素。

在前面我们说过,当产品越来越多,会使得工厂越来越难管理,要么工厂的数量越来越多,要么工厂本身越来越复杂,所以,这里介绍了抽象工厂模式,用于产生较为复杂的产品结构下的工厂,它与工厂方法最基本的区别是抽象工厂模式能够创建不同种类的产品,也就能够更加方便地基于抽象的概念管理一大堆复杂的产品对象。

首先我们介绍两个概念:产品族与产品等级。

所谓产品族,就是由功能相关联的不同种类产品组成的家族,比如我们最终所需要的低级神仙食物,它是由低级蟠桃与低级仙丹组成的。而产品等级就是对于某一种类的产品,内部划分的等级结构,如蟠桃内部被划分为低级、中级与高级,产品等级是面向同一种类的产品的内部区别描述。

在一开始,我们需要创建一个抽象工厂,这个抽象工厂中描述了每个具体工厂需要提供哪些实现。然后针对每一个产品族创建一个工厂,用于统一创建不同类型的产品。类图如下:

从图中可以看到,不同等级的产品交给了不同的工厂去创建,用户只需要调用自己的目标产品族对应的工厂,获取最终的产品族即可,至于这个产品系列内部结构如何变化,用户并不需要关心。接下来是具体的实现:

蟠桃

package com.tirion.design.abstraction.factory;

public interface FlatPeach {

    void printLevel();

    void printCycleTime();
}

低级蟠桃

package com.tirion.design.abstraction.factory;

public class LowLevelFlatPeach implements FlatPeach {

    LowLevelFlatPeach(){
printCycleTime();
printLevel();
} @Override
public void printLevel() {
System.out.println("低级蟠桃");
} @Override
public void printCycleTime() {
System.out.println("三千年一熟");
} }

中级蟠桃

package com.tirion.design.abstraction.factory;

public class MiddleLevelFlatPeach implements FlatPeach {

    MiddleLevelFlatPeach(){
printCycleTime();
printLevel();
} @Override
public void printLevel() {
System.out.println("中级蟠桃");
} @Override
public void printCycleTime() {
System.out.println("六千年一熟");
} }

高级蟠桃

package com.tirion.design.abstraction.factory;

public class HighLevelFlatPeach implements FlatPeach {

    HighLevelFlatPeach(){
printCycleTime();
printLevel();
} @Override
public void printLevel() {
System.out.println("高级蟠桃");
} @Override
public void printCycleTime() {
System.out.println("九千年一熟");
} }

仙丹

package com.tirion.design.abstraction.factory;

public interface Elixir {

    void printLevel();

    void printCycleTime();
}

低级仙丹

package com.tirion.design.abstraction.factory;

public class LowLevelElixir implements Elixir {

    LowLevelElixir(){
printCycleTime();
printLevel();
} @Override
public void printLevel() {
System.out.println("低级仙丹");
} @Override
public void printCycleTime() {
System.out.println("炼三三得九天");
} }

中级仙丹

package com.tirion.design.abstraction.factory;

public class MiddleLevelElixir implements Elixir {

    MiddleLevelElixir(){
printCycleTime();
printLevel();
} @Override
public void printLevel() {
System.out.println("中级仙丹");
} @Override
public void printCycleTime() {
System.out.println("炼七七四十九天");
} }

高级仙丹

package com.tirion.design.abstraction.factory;

public class HighLevelElixir implements Elixir {

    HighLevelElixir(){
printCycleTime();
printLevel();
} @Override
public void printLevel() {
System.out.println("高级仙丹");
} @Override
public void printCycleTime() {
System.out.println("炼九九八十一天");
} }

抽象工厂-神仙食物工厂

package com.tirion.design.abstraction.factory;

public interface XianFoodFactory {

    FlatPeach prepareFlatPeach();

    Elixir prepareElixir();

}

低级神仙食物工厂

package com.tirion.design.abstraction.factory;

public class LowLevelXianFoodFactory implements XianFoodFactory {

    @Override
public FlatPeach prepareFlatPeach() {
return new LowLevelFlatPeach();
} @Override
public Elixir prepareElixir() {
return new LowLevelElixir();
} }

中级神仙食物工厂

package com.tirion.design.abstraction.factory;

public class MiddleLevelXianFoodFactory implements XianFoodFactory {

    @Override
public FlatPeach prepareFlatPeach() {
return new MiddleLevelFlatPeach();
} @Override
public Elixir prepareElixir() {
return new MiddleLevelElixir();
} }

高级神仙食物工厂

package com.tirion.design.abstraction.factory;

public class HighLevelXianFoodFactory implements XianFoodFactory {

    @Override
public FlatPeach prepareFlatPeach() {
return new HighLevelFlatPeach();
} @Override
public Elixir prepareElixir() {
return new HighLevelElixir();
} }

王母娘娘-调用者

package com.tirion.design.abstraction.factory;

public class TheQueenMother {

    public static void prepareXianFood(XianFoodFactory xianFoodFactory) {
xianFoodFactory.prepareFlatPeach();
xianFoodFactory.prepareElixir();
} public static void main(String[] args) {
System.out.println("准备低级神仙食物...");
TheQueenMother.prepareXianFood(new LowLevelXianFoodFactory());
System.out.println("准备中级神仙食物...");
TheQueenMother.prepareXianFood(new MiddleLevelXianFoodFactory());
System.out.println("准备高级神仙食物...");
TheQueenMother.prepareXianFood(new HighLevelXianFoodFactory());
}
}

代码执行结果

准备低级神仙食物...
三千年一熟
低级蟠桃
炼三三得九天
低级仙丹
准备中级神仙食物...
六千年一熟
中级蟠桃
炼七七四十九天
中级仙丹
准备高级神仙食物...
九千年一熟
高级蟠桃
炼九九八十一天
高级仙丹

使用了抽象工厂模式之后,在面对复杂的宴会菜单对象时,王母娘娘不需要关心天宫的御厨如何搭配食物,只需要下达命令要求御厨准备不同等级的食物套餐就可以了。

每个具体工厂只需要创建自己负责的产品,这符合单一职责原则。

具体工厂返回的产品是产品的抽象而不是具体,所以符合依赖导致原则。

关于开闭原则,抽象工厂模式是一个比较典型的例子。

我们在使用中可以发现,如果要添加一个新的产品族,比如王母娘娘专享食物套餐,套餐内容是高级蟠桃,而并不需要吃仙丹(王母娘娘吃仙丹已经没啥用了),那么我们只需要增加一个TheQueenMotherFoodFactory,然后在内部添加具体的实现即可,并不需要更改其他任何类,很完美地符合了开闭原则。

王母娘娘食物工厂

package com.tirion.design.abstraction.factory;

public class TheQueenMotherFoodFactory implements XianFoodFactory {

    @Override
public FlatPeach prepareFlatPeach() {
return new HighLevelFlatPeach();
} @Override
public Elixir prepareElixir() {
return null;
} }

但是如果某一天,镇元大仙上供了一批人参果,王母娘娘一高兴,把人参果也作为宴会的一道主菜,那么就麻烦了:不仅仅抽象工厂XianFoodFactory要增加人参果的接口,它的所有实现都要增加相应的接口实现,整个体系才能继续运转下去。这时候,抽象工厂模式又不符合开闭原则了。

根据以上描述我们可以得出,对于抽象工厂模式,增加产品族符合开闭原则,增加产品种类则不符合开闭原则,也就是说抽象工厂模式具备开闭原则的倾斜性。

注意:抽象工厂模式并不是比工厂方法模式更加高级的模式,而是为了适应不同的业务变化情况而做出的不同应对,继而产生的不同解决方案而已。

抽象工厂模式的使用情景:

1.系统中存在多个产品族,用户只关心产品族,也就是只关心最终结果

2.属于同一产品族的产品相互之间具有关联关系,它们是被组合在一起使用的

抽象工厂模式遵循的设计原则:

1.依赖倒置原则(客户端依赖的是产品抽象而不是具体产品)

2.迪米特法则

3.里氏替换原则

4.接口隔离原则(使用了多个相互隔离的接口,降低了耦合度)

5.单一职责原则(每个工厂只要负责创建自己对应产品族的产品)

6.开闭原则(具有倾斜性,支持新增产品族,但不支持新增产品类型)

关于抽象工厂模式的介绍就到这里,你可以将它记忆为蟠桃宴会模式

如果你认为文章中哪里有错误或者不足的地方,欢迎在评论区指出,也希望这篇文章对你学习java设计模式能够有所帮助。转载请注明,谢谢。

更多设计模式的介绍请到悟空模式-java设计模式中查看。

悟空模式-java-抽象工厂模式的更多相关文章

  1. Java设计模式之【工厂模式】(简单工厂模式,工厂方法模式,抽象工厂模式)

    Java设计模式之[工厂模式](简单工厂模式,工厂方法模式,抽象工厂模式) 工厂模式出现的原因 在java中,创建一个对象最简单的方法就是使用new关键字.但在一些复杂的业务逻辑中,创建一个对象不只需 ...

  2. Java抽象工厂模式

    Java抽象工厂模式 基本定义 抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的.抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象 ...

  3. Java开发中的23中设计模式详解(一)工厂方法模式和抽象工厂模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

  4. Java设计模式(3)——创建型模式之抽象工厂模式(Abstract Factory)

    一.概述 抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象. UML图: 其他的过多概念不再 ...

  5. java设计模式 -------- 创建模式 之 抽象工厂模式

    本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 工厂方法模式和抽象工厂模式不好区分清楚: 工厂方法模式特点: 1. 一个抽象产品 ...

  6. JAVA中的工厂方法模式和抽象工厂模式

    工厂方法模式: 定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类.类型:创建类模式类图: 类图知识点:1.类图分为三部分,依次是类名.属性.方法2.以& ...

  7. [19/04/23-星期二] GOF23_创建型模式(工厂模式、抽象工厂模式)

    一.工厂模式(分为:简单工厂模式.工厂方法模式.抽象工厂模式) 实现了创建者和调用者的分离 核心本质:1.实例化对象,用工厂方法代替new操作:2.将选择实现类.创建对象统一管理和控制,从而将调用者跟 ...

  8. python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)

    十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...

  9. c#工厂模式与抽象工厂模式

    一. 工厂方法(Factory Method)模式 工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中. 工厂方法模式是简单工 ...

  10. PHP简单工厂模式、工厂方法模式和抽象工厂模式比较

    PHP工厂模式概念:工厂模式是一种类,它具有为您创建对象的某些方法.您可以使用工厂类创建对象,而不直接使用 new.这样,如果您想要更改所创建的对象类型,只需更改该工厂即可.使用该工厂的所有代码会自动 ...

随机推荐

  1. leetcode 78. 子集 JAVA

    题目: 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: nums = [1,2,3] 输出: [ [3],   [1], ...

  2. 使用browserSync自动刷新

    本篇主要是以 http://www.imooc.com/article/14759 为参考来写的: 已经整理到github上:https://github.com/Macaulish/gulp-Bro ...

  3. tomcat安装配置常见问题详解

    历经波折,终于把tomcat装好了.记录下过程供自己和后来的初学者参考吧! 本文先后介绍了tomcat的下载安装方法.安装和启动不成功的常见原因 以及启动tomcat后如何配置上下文. 一.下载安装 ...

  4. [Swift实际操作]七、常见概念-(8)日历Calendar和时区TimerZone

    本文将为你演示日历的一些属性,以及如何利用日历,查询是否为昨天.今天和明天. 首先引入需要用到的界面工具框架 import UIKit 然后生成一个日历对象,并获得用户当前的日历. var calen ...

  5. 使用TopShelf做windows服务

    class Program { static void Main(string[] args) { HostFactory.Run(x => { x.RunAsLocalSystem(); x. ...

  6. (转)python函数: 内置函数

    原文:https://blog.csdn.net/pipisorry/article/details/44755423 https://juejin.im/post/5ae3ee096fb9a07aa ...

  7. (转) centos7下创建mysql5.6多实例

    原文:http://blog.csdn.net/a1010256340/article/details/77483504 一.mysql安装目录说明mysql5.6以二进制安装包安装在/data/my ...

  8. 如何虚拟机里安装Win8操作系统

    不多说,直接上干货! Windows Server 2003.2008.2012系统的安装 推荐网址:打开MSDN网站(http://msdn.itellyou.cn ) 关于给电脑换系统,很多人会花 ...

  9. 自然语言处理--Word2vec(一)

    一.自然语言处理与深度学习 自然语言处理应用 深度学习模型                       为什么需要用深度学习来处理呢 二.语言模型 1.语言模型实例: 机器翻译 拼写纠错        ...

  10. mongodb-手写mongoclient加入到springmvc中

    由于一个项目使用的是springmvc3.x版本, mongodb使用的为3.x版本, 所以springmvc继承的mongodb-data并不可用, 只能自己手写一个mongoclient并加入到s ...