重温设计模式之 Factory 设计模式的工厂模式
liebian365 2024-10-21 08:46 26 浏览 0 评论
前言
创建型模式的核心干将,工厂、简单工厂、抽象工厂,还记得清么,一文回顾和对比下。
一 为什么需要工厂
系统中总是需要创建对象的,一般使用new()来创建对象。创建对象可以是简单的new(),也可以有复杂的加工逻辑,如果在主程序中创建对象,那么就是将主干逻辑和创建对象的非主干逻辑耦合在了一起,工厂模式要做的就是将非核心的对象创建逻辑与主干逻辑解耦,通过调用工厂的创建方法直接获取到一个对象。
二 工厂模式中的角色划分
- 抽象产品角色(都有)
- 具体产品角色(都有)
- 抽象工厂角色(工厂方法模式和抽象工厂模式有)
- 具体工厂角色(都有)
- 上下文角色(都有)——调用工厂获取对象
三 对工厂的基本认知
工厂方法总是基于一定的入参,返回对应的产品对象,即工厂是用来生产产品的。
工厂方法可能根据不同条件创建不同的具体产品实体,因此工厂方法的返回类型是抽象产品类型。
四 工厂模式的简单划分
1 简单工厂模式
产品有抽象层,但是工厂没有抽象层,在一个工厂中根据传参创建相应的产品类型。
如果需要新增产品族(例如在A_cpu,B_cpu之外新增C_cpu),那么需要在工厂方法中进行逻辑修改,没有做到开闭原则——对扩展开放,对修改封闭。
简单工厂模式就是静态工厂模式,不属于GOF23中的模式,就是一个简单的封装,在静态工厂模式中,工厂方法是静态的,所以叫做静态工厂方法。
2 工厂方法模式
产品有抽象层,工厂也有抽象层,一个工厂对应一个产品(即一个工厂只能创建一个产品类别)。
如果新增产品,只需要新增工厂,不需要对原有工厂逻辑进行修改,符合开闭原则。
3 抽象工厂模式
产品有抽象层,工厂有抽象层,一个工厂对应多个产品(即一个工厂可以创建多个产品类别)。
用于解决有多有产品类别(芯片、主板、显卡)情况下,产品族(A产品族、B产品族)的切换替代问题。
五 简单工厂模式详解
简单工厂模式下,只有一个工厂类,工厂角色没有抽象层次。
使用这一个工厂生产出不同的产品实现,例如使用CpuFactory这一个产品类中会生产出ACpu、BCpu等具体的产品实现。
如果要新增产品实现,例如CCpu,需要修改该工厂方法的代码。
简单工厂模式中,决定生成哪个产品的逻辑在工厂内实现。
1 DEMO:抽象产品接口
package com.taobao.migao.pattern.factory.simplefactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品抽象接口:CPU
*/
public interface Cpu {
void calculate();
}
2 DEMO:具体产品实现
package com.taobao.migao.pattern.factory.simplefactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品的具体实现-A的CPU
*/
public class ACpu implements Cpu {
@Override
public void calculate() {
System.out.println("this is A cpu");
}
}
3 DEMO:具体产品实现
package com.taobao.migao.pattern.factory.simplefactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品的具体类型-B的CPU
*/
public class BCpu implements Cpu {
@Override
public void calculate() {
System.out.println("this is B cpu");
}
}
4 DEMO:简单工厂类
package com.taobao.migao.pattern.factory.simplefactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 简单工厂类:CPU的工厂
*/
public class CpuFactory {
/**
* 返回值是产品的抽象类型
* 简单工厂模式:创建哪种具体产品类型代码在工厂内部,如果需要新增具体产品,需要修改工厂类方法
* 例如需要增加C的cpu,需要修改下面的工厂方法,不符合开-闭原则
* @return
*/
public static Cpu createCpu(Class classType) {
if (classType.getName().equals(ACpu.class.getName())) {
return new ACpu();
} else if (classType.getName().equals(BCpu.class.getName())) {
return new BCpu();
}
return null;
}
}
5 DEMO:测试类——调用工厂创建对象的客户端代码
package com.taobao.migao.pattern.factory.simplefactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 简单工厂测试类,对应程序中需要创建对象并调用对象方法的客户端代码
*/
public class SimpleFactoryTest {
public static void main(String[] args) {
Cpu cpu = CpuFactory.createCpu(BCpu.class);
cpu.calculate();
}
}
六 工厂方法模式详解
工厂方法模式中,对工厂也进行了抽象,一个抽象工厂还是对应一个产品类别,例如CpuFacroy接口对应生产Cpu产品,但是具体生产的时候,将具体的产品实现交给每个具体的工厂实现去生产;即在CpuFactory接口下,有ACpuFactory和BCpuFactory,分别来生产ACpu和BCpu这2中具体的产品。
工厂方法模式中具体的工厂负责创建具体的产品,工厂内部的逻辑只负责创建对应对象,决定生成什么产品的逻辑在外部客户端,客户端通过选择使用具体工厂,间接决定了生成什么产品。
1 DEMO:产品抽象接口
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品抽象接口:CPU
*/
public interface Cpu {
void calculate();
}
2 DEMO:具体产品实现
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品的具体实现-A的CPU
*/
public class ACpu implements Cpu {
@Override
public void calculate() {
System.out.println("this is A cpu");
}
}
3 DEMO:具体产品实现
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品的具体类型-B的CPU
*/
public class BCpu implements Cpu {
@Override
public void calculate() {
System.out.println("this is B cpu");
}
}
4 DEMO:抽象工厂
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description CPU这个产品类型的抽象工厂
*/
public interface CpuFactory {
/**
* 这是CPU产品的工厂,所以专门生产CPU,返回的类型是对应产品的抽象类型
*/
Cpu createCpu();
}
5 DEMO:具体工厂实现
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 工厂方法模式下,一个工厂对应一个产品:一个抽象工厂对应抽象产品,一个具体工厂对应一个具体产品
*/
public class ACpuFactory implements CpuFactory{
@Override
public Cpu createCpu() {
return new ACpu();
}
}
6 DEMO:具体工厂实现
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 工厂方法模式下,一个工厂对应一个产品:一个抽象工厂对应抽象产品,一个具体工厂对应一个具体产品
*/
public class BCpuFactory implements CpuFactory {
@Override
public Cpu createCpu() {
return new BCpu();
}
}
7 DEMO:测试类——上下文
package com.taobao.migao.pattern.factory.factorymethod;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 测试类 使用具体的工厂实现来创建产品对象
*/
public class FactoryMethodTest {
public static void main(String[] args) {
CpuFactory factory = new ACpuFactory();
Cpu cpu = factory.createCpu();
cpu.calculate();
}
}
七 THINK:简单工厂&工厂方法模式的区别
简单工厂模式中工厂类没有抽象层,而工厂方法模式中工厂类有抽象工厂。
决定生成具体什么产品的逻辑在哪里实现?
- 简单工厂模式中,客户端决定传递什么类型的参数,在工厂中根据不同的参数决定创建不同的对象,即工厂内部有决策创建产品的逻辑。
- 工厂方法模式中,具体工厂内部很纯净,什么类型的工厂就负责创建对应的产品,决策的逻辑全部在客户端中实现。
当需要新增产品实现时,简单工厂模式需要修改工厂逻辑,工厂方法模式只需要新增具体工厂实现,不需要修改工厂内部逻辑。
八 THINK:工厂方法 & 抽象工厂模式的区别
1 工厂方法模式
工厂方法模式用于解决一个产品(Cpu),有多个产品族(ACpu,BCpu)的情况,以抽象产品作为工厂,例如CpuFactory,每个产品族对应一个具体工厂,例如ACpuFactory,BCpuFactory,即工厂方法模式以产品维度来建厂。
工厂方式模式中,多一个新的抽象产品的话需要新建立一个抽象工厂,例如新建MainboardFactory等。即如果需要新增产品线(XianKa),则需要新增抽象工厂(XianKaFactory);如果需要在某个产品(Cpu)下新增具体产品,则需要新增具体工厂(CCpuFactory)。
工厂方法模式中以抽象产品维度建厂,每个抽象产品一个工厂,当产品族(A,B,C……)增加的时候,需要为每个产品的抽象工厂新增具体工厂(CCpuFactory,CMainboardFactory,CXianKaFactory)。
2 抽象工厂模式
在工厂方法模式下,当产品线(品类:cpu/主板/显卡)和产品族(A/B/C)水平扩展后,如果要新增产品族,那么需要在所有工厂下面新增新产品族的所有产品,即在cpu工厂、主板工厂、显卡工厂……都新增C的具体工厂,这样显然改动太大,此时就要考虑使用抽象工厂模式。
抽象工厂模式下,以产品族维度来建厂,一个厂里有多个创建方法,每个创建方法负责创建一个产品线,例如有A工厂、B工厂,每个工厂里面有创建cpu的方法、创建主板的方法、创建显卡的方法,当需要新增一个产品族的时候,只需要新增一个工厂,例如C工厂,在该工厂中创建各个产品即可。
3 总结
工厂方法模式和抽象工厂模式的最大区别是工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。
九 抽象工厂模式详解
1 抽象工厂模式角色
- 抽象产品
- 具体产品
- 抽象工厂:以产品族维度建工厂类,类中含有多个抽象方法,每个方法对应创建一个产品。
- 具体工厂:具体工厂实现抽象工厂,并实现里面的所有产品创建方法,创建属于当前具体产品对象。
- 环境类:持有抽象工厂,并可以在运行时注入具体工厂。
2 DEMO:抽象产品
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品抽象接口:CPU
*/
public interface Cpu {
void calculate();
}
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 抽象产品:主板
*/
public interface Mainboard {
void installCpu();
}
3 DEMO:具体产品
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品的具体实现-A的CPU
*/
public class ACpu implements Cpu {
@Override
public void calculate() {
System.out.println("this is A cpu");
}
}
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 产品的具体实现-B的CPU
*/
public class BCpu implements Cpu {
@Override
public void calculate() {
System.out.println("this is B cpu");
}
}
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description
*/
public class AMainboard implements Mainboard {
@Override
public void installCpu() {
System.out.println("this is A mainboard");
}
}
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description
*/
public class BMainboard implements Mainboard {
@Override
public void installCpu() {
System.out.println("this is B mainboard");
}
}
4 DEMO:抽象工厂
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 抽象工厂,定义了工厂需要负责创建的产品
*/
public interface AbatractFactory {
//创建CPU产品
Cpu createCpu();
//创建主板产品
Mainboard createMainboard();
}
5 DEMO:具体工厂
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 具体的工厂,以产品族维度建立具体的工厂
*/
public class AFactory implements AbatractFactory {
@Override
public Cpu createCpu() {
return new ACpu();
}
@Override
public Mainboard createMainboard() {
return new AMainboard();
}
}
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 具体工厂,以产品族维度建立具体的工厂
*/
public class BFactory implements AbatractFactory {
@Override
public Cpu createCpu() {
return new BCpu();
}
@Override
public Mainboard createMainboard() {
return new BMainboard();
}
}
6 DEMO:测试类——类似程序上下文
package com.taobao.migao.pattern.factory.abstractfactory;
/**
* @author <a href="mailto:migao.jjm@alibaba-inc.com">jiongmin.jjm</a>
* @version 1.0
* @description 抽象工厂测试类,持有具体的工厂实例,调用工厂的方法获取具体的产品对象
*/
public class AbstractFactoryTest {
public static void main(String[] args) {
//注入A工厂
AbatractFactory factory = new AFactory();
Cpu cpu = factory.createCpu();
Mainboard mainboard = factory.createMainboard();
cpu.calculate();
mainboard.installCpu();
}
}
十 THINK:工厂模式中的方法一定是静态的吗?
在简单工厂中,工厂方法没有对应的抽象,可以定义为静态的。
在工厂方法模式和抽象工厂模式中,工厂都有对应的抽象接口,而接口中的抽象方法不能定义为静态,所以工厂方法也不能是静态的。
十一 THINK:对于接口中static的理解
接口interface以及接口中的方法都是public abstract的。
接口中的方法都是抽象方法,没有方法体,因此也不允许使用static来修饰(static方法表示可以被类调用,接口因为没有功能体,所以没有人调用,所以不允许声明为static)。
但是从JDK8开始,接口中方法可以有static,此时的方法必须有方法体,即接口中可以含有非抽象的方法,和抽象类一样了,接口中非抽象的方法不需要被实现,抽象的方法必须要求子类实现。
十二 工厂模式 & 抽象工厂的使用场景
一个系统不应当依赖于产品类实例如何被创建、组合、表达的细节,这是所有工厂模式都要关注解决的问题。
当系统中的产品有多个产品族,虽然对于任何一个具体请求只属于其中一个产品族,但是对于系统而言,应当面向产品族设计,即使用抽象工厂模式。
当系统中有多个产品族,并且这个产品族中的产品通常是在一起使用,一起创建的,如果这种约束需要在系统设计中体现出来,那么应当使用抽象工厂模式(例如:不管是A产品族,还是B产品族中的芯片、主板、磁盘这些产品通常需要一起创建)。
十三 抽象工厂模式的优缺点
1 抽象工厂的优点
分离了接口和实现
客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口,也就是说客户端从具体的产品中实现了解耦。
使切换产品族变得容易
因为一个具体的工厂代表的是一个产品族,比如上面例子中的A系列到B系列只需要切换一下具体的工厂。
2 抽象工厂的缺点
不太容易扩展新的产品
如果需要给这个产品族添加一个新的产品,那么就需要修改抽象工厂,需要在抽象工厂中添加新产品创建方法,同时需要给所有的具体工厂增加接口。
十四 最佳实践
都使用抽象工厂模式,按照产品族维度来建立工厂,如果只有一个产品那么工厂中就一个方法,如果有多个产品就多个方法。
原文:https://mp.weixin.qq.com/s/ZQmys84pgfIkWuYU6ClngQ
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)