悟空模式-java-抽象工厂模式
【一朝,王母娘娘设宴,大开宝阁,瑶池中做蟠桃胜会】
有一天,王母娘娘要在瑶池办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-抽象工厂模式的更多相关文章
- Java设计模式之【工厂模式】(简单工厂模式,工厂方法模式,抽象工厂模式)
Java设计模式之[工厂模式](简单工厂模式,工厂方法模式,抽象工厂模式) 工厂模式出现的原因 在java中,创建一个对象最简单的方法就是使用new关键字.但在一些复杂的业务逻辑中,创建一个对象不只需 ...
- Java抽象工厂模式
Java抽象工厂模式 基本定义 抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的.抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象 ...
- Java开发中的23中设计模式详解(一)工厂方法模式和抽象工厂模式
一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...
- Java设计模式(3)——创建型模式之抽象工厂模式(Abstract Factory)
一.概述 抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象. UML图: 其他的过多概念不再 ...
- java设计模式 -------- 创建模式 之 抽象工厂模式
本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 工厂方法模式和抽象工厂模式不好区分清楚: 工厂方法模式特点: 1. 一个抽象产品 ...
- JAVA中的工厂方法模式和抽象工厂模式
工厂方法模式: 定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类.类型:创建类模式类图: 类图知识点:1.类图分为三部分,依次是类名.属性.方法2.以& ...
- [19/04/23-星期二] GOF23_创建型模式(工厂模式、抽象工厂模式)
一.工厂模式(分为:简单工厂模式.工厂方法模式.抽象工厂模式) 实现了创建者和调用者的分离 核心本质:1.实例化对象,用工厂方法代替new操作:2.将选择实现类.创建对象统一管理和控制,从而将调用者跟 ...
- python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)
十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...
- c#工厂模式与抽象工厂模式
一. 工厂方法(Factory Method)模式 工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中. 工厂方法模式是简单工 ...
- PHP简单工厂模式、工厂方法模式和抽象工厂模式比较
PHP工厂模式概念:工厂模式是一种类,它具有为您创建对象的某些方法.您可以使用工厂类创建对象,而不直接使用 new.这样,如果您想要更改所创建的对象类型,只需更改该工厂即可.使用该工厂的所有代码会自动 ...
随机推荐
- zoj3497 Mistwald(矩阵快速幂)
题意:给定一个有向图(最多25个节点,每个节点的出度最多为4),给定起点和终点,然后从起点开始走,走到终点就停止,否则一直往下走,问能不能P步到达终点.也就是说从起点出发,走一条长度为P的路径,路径中 ...
- 在node中使用promise上传图片到七牛云
为了分摊个人服务器压力.提升图片下载上传的速度,使用七牛云保存用户上传的图片. 后台基于express搭建的,上传使用七牛云第三方nodejs-sdk.由于七牛云上传图片只能单个进行,并且考虑到上传完 ...
- WKWebView 里 JS 和 native 通信的例子
native 端 初始化 wkwebview,设置 message handler webView = WKWebView.init() let usecc = self.webView.config ...
- POJ 1083
#include<iostream> #include<stdio.h> #include<algorithm> #define MAXN 400 using na ...
- C#设计模式系列目录
http://www.cnblogs.com/libingql/archive/2012/04/16/2451608.html 抽空,学习,加强!
- 【树】Populating Next Right Pointers in Each Node
题目: Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode ...
- ES6-Array
/* * 数组解构赋值: * ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这种被称为解构. * 示例如下: */ var [a,b,c] = [1,2,3]; console.log ...
- ConfigurationManager
ConfigurationManager读取和写入 提供对客户端应用程序配置文件的访问 通过引入System.Configuration.dll可以用ConfigurationManager类来读取项 ...
- SpringMVC 之 Hello World 入门
1 准备开发环境和运行环境 依赖 jar 包下载,如下图所示: 2 前端控制器的配置 在我们的web.xml中添加如下配置: <!-- The front controller of this ...
- 169.254地址无网关信息 ----- 解决方案 启动DHCP服务
169.254.X.X是Windows操作系统在DHCP信息租用失败时自动给客户机分配的IP地址,.看到地址的时候没有网关. 解决方案 启动DHCP服务 1. 首先确认 路由器 DHCP 服务已 ...