【设计模式】之工厂模式(三种)

系列文章目录

  • 【设计模式】之单例模式

  • 【设计模式】之模板方法模式

  • 【设计模式】之责任链模式

  • 【设计模式】之策略模式

前言

今天给大家介绍23种设计模式中的工厂模式,学过Spring的小伙伴应该不陌生,今天给大家详细介绍一下它。🌈

注意:文章若有错误的地方,欢迎评论区里面指正 🍭 


1、工厂模式的分类

工厂模式可以分为三类:

  • 简单工厂模式(Simple Factory)

  • 工厂方法模式(Factory Method)

  • 抽象工厂模式(Abstract Factory)

2、什么是工厂模式

        工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方式,使得代码更加灵活可维护可扩展。在工厂模式中,对象的创建不再由调用者直接负责,而是通过一个专门的工厂类来负责创建。这样,调用者就无需关心对象的创建细节,只需向工厂类请求所需的对象即可。

3、工厂模式的角色

  1. 产品(Product):定义了产品的接口或抽象类,描述了产品的主要功能和特性。
  2. 具体产品(Concrete Product):实现了产品接口或继承了产品抽象类的具体类,是工厂类创建的目标。
  3. 工厂(Factory):负责创建产品的工厂接口或抽象类,其中包含了创建产品的方法。
  4. 具体工厂(Concrete Factory):实现了工厂接口或继承了工厂抽象类的具体类,负责具体创建产品的实例。

4、工厂模式的优点在哪里

  • 解耦:将对象的创建与使用分离,降低了代码之间的耦合度。
  • 灵活性:可以很容易地创建不同的产品实例,只需修改工厂类的实现即可。
  • 可扩展性:当需要添加新产品时,只需添加新的具体工厂和具体产品类,无需修改原有代码。
  • 易于维护:将对象的创建封装在工厂类中,使得代码更加清晰和易于维护。

一、简单工厂模式

1、简单工厂模式的角色

简单工厂的角色如下:

抽象产品定义了产品的接口或抽象类,描述了产品的主要功能和特性。它是所有具体产品的基类,为它们提供了统一的接口
具体产品实现了产品接口或继承了产品抽象类的具体类,是简单工厂模式创建的目标
简单工厂负责创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。

2、简单工厂模式的示例

定义一个抽象的手机产品Phone

public interface Phone {void showBrand();
}

定义具体手机产品HuaWeiThreeStarApple

public class HuaWei implements Phone{@Overridepublic void showBrand() {System.out.println("这是一个华为手机。");}
}public class ThreeStar implements Phone{@Overridepublic void showBrand() {System.out.println("这是一个三星的手机。");}
}public class Apple implements Phone{@Overridepublic void showBrand() {System.out.println("这是一个苹果手机。");}
}

定义手机工厂PhoneFactory

public class PhoneFactory {public static Phone showPhone(String brandName){if ("HuaWei".equals(brandName)){return new HuaWei();}if ("ThreeStar".equals(brandName)){return new ThreeStar();}if ("Apple".equals(brandName)){return new Apple();}return null;}
}

测试:

public class PhoneTest {public static void main(String[] args) {Phone huaWei = PhoneFactory.showPhone("HuaWei");if (null != huaWei) huaWei.showBrand();else System.out.println("无法生成该品牌的手机。");}
}
//测试结果:/*这是一个华为手机。    */

在简单工厂模式中,抽象产品既可以是各个具体产品类实现的共同的接口,也可以是各个具体产品类继承的抽象父类。

3、简单工厂模式使用场景

  1. 创建对象不涉及复杂的逻辑:当创建对象时,不需要考虑太多的逻辑和条件判断,只是简单地根据传入的参数返回对应类型的实例时,可以使用简单工厂模式。

  2. 减少客户端代码对类的依赖:在客户端代码中,如果直接依赖于多个具体的类,会导致代码变得复杂且难以维护。使用简单工厂模式,客户端只需要依赖于工厂接口,从而降低了代码之间的耦合度。

  3. 需要动态地选择具体的类:在某些情况下,客户端可能需要根据运行时的情况动态地选择创建哪个类的实例。简单工厂模式可以根据传入的参数或条件来选择并创建相应的对象。

  4. 创建对象需要消耗较多资源:如果创建对象需要消耗较多的资源或执行复杂的初始化操作,使用简单工厂模式可以将这些操作封装在工厂类中,从而简化了客户端代码,并提高了代码的可读性和可维护性。

  5. 创建对象需要遵守一些约束或规则:在某些情况下,创建对象需要遵守一些约束或规则,例如,需要确保在单例模式下只创建一个实例,或者在创建对象前需要进行一些验证操作。简单工厂模式可以在工厂类中实现这些约束或规则,从而确保创建的对象符合预期的要求。

4、简单工厂模式总结

优点:

        简单工厂模式通过把对象的创建过程封装在简单工厂类中,使得客户端与具体产品类解耦,提高了系统的灵活性和可扩展性

缺点:

        当需要添加新产品时,需要修改简单工厂类的代码,这违反了开闭原则(对扩展开放,对修改关闭)

二、工厂方法模式

工厂方法模式:它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。

1、工厂方法模式的角色:

抽象产品这是定义产品的接口,是工厂方法模式所创建的对象的超类型,也就是产品对象的公共父类。
具体产品它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
抽象工厂在抽象工厂类中声明了工厂方法,用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
具体工厂它是抽象工厂的实现类,实现了在抽象工厂中声明的工厂方法,并可由客户端调用,返回一个具体产品类的实例。

2、工厂方法模式的示例

抽象工厂PhoneFactory 

public interface PhoneFactory {Phone CreatePhone();
}

抽象产品Phone 

public interface Phone {void showBrand();
}

具体产品工厂HuaWeiFactory、ThreeStarFactory、AppleFactory 

public class HuaWeiFactory implements PhoneFactory{@Overridepublic Phone CreatePhone() {System.out.println("这是华为手机工厂,这里只生产华为手机。");return new HuaWei();}
}public class ThreeStarFactory implements PhoneFactory{@Overridepublic Phone CreatePhone() {System.out.println("这是三星手机工厂,这里只生产三星手机。");return new ThreeStar();}
}public class AppleFactory implements PhoneFactory{@Overridepublic Phone CreatePhone() {System.out.println("这是苹果手机工厂,这里只生产苹果手机。");return new Apple();}
}

具体产品跟简单工厂的一样,还是HuaWei、ThreeStar、Apple那三个。

测试:

public class test {public static void main(String[] args) {HuaWeiFactory huaWeiFactory = new HuaWeiFactory();Phone phone = huaWeiFactory.CreatePhone();phone.showBrand();}
}
//测试结果:/*这是华为手机工厂,这里只生产华为手机。这是一个华为手机。*/

3、工厂方法模式使用场景

  • 重复代码:当创建对象需要使用大量重复的代码时,工厂方法模式可以通过定义一个单独的创建实例对象的方法,来解决这个问题。
  • 不关心创建过程:如果客户端不依赖产品类,不关心实例如何被创建、实现等细节,那么工厂方法模式是一个好选择。客户端只需要知道所对应的工厂,而具体的产品对象,由对应的工厂创建。
  • 子类指定创建对象:当一个类希望由子类来指定它所创建的对象时,工厂方法模式也是一个不错的选择。
  • 需要提供默认值和允许自定义值:如果一个类需要提供一些默认值,同时允许用户自定义这些值,工厂方法模式同样适用。

4、工厂方法模式总结

优点

  1. 解耦:使用工厂方法可以让用户的代码和某个特定类的子类的代码解耦。
  2. 无需关心创建细节:用户不必知道它使用的对象是怎么样被创建的,只需知道该对象有哪些方法即可。
  3. 符合“开放-封闭”原则:工厂方法模式改变了我们直接用new创建对象的方式,使得在添加新产品时,只是扩展的变化,而不是修改的变化,这完全符合“开放-封闭”原则。

缺点

  1. 增加类的数量:随着具体产品数量的增加,工厂类的数量也会增加,导致类的数量增多。
  2. 增加系统复杂度:由于需要定义多个工厂类,所以增加了系统的复杂度。对于系统的设计和维护都会带来很多困扰。
  3. 增加代码量:工厂方法模式需要定义抽象工厂类和抽象产品类,并且每个具体产品都需要一个对应的具体工厂类和具体产品类。这导致了代码的数量增加,增加了开发量和维护成本。
  4. 违背开闭原则:在添加新产品时,需要新增具体产品类和对应的具体工厂类。这违背了开闭原则,对于已有代码的修改会对系统稳定性造成一定的影响,需要进行大量的修改和测试。
  5. 运行效率低:由于工厂方法模式每次都需要通过具体工厂类来创建具体产品类的实例,这就需要实例化具体工厂类和具体产品类,可能导致运行效率较低。

三、抽象工厂模式

1、抽象工厂模式角色

抽象工厂声明创建抽象产品对象的一个接口(有几个产品组,则声明几个方法。比如对于上述的场景,需要声明一个用于生产篮球类产品的方法,还需要声明一个用于生产足球类产品的方法)
具体工厂实现了抽象工厂接口,负责实例化具体产品类。每个具体工厂都对应一组相互关联或相互依赖的产品对象。
抽象产品定义了产品的接口,是工厂方法所创建对象的超类型,或者是所创建对象的接口。
具体产品实现了抽象产品接口,是某种类型的具体产品对象

2、抽象工厂模式示例

抽象工厂:

public interface AbstractFactory {PhoneFactory CreateApplePhone();BookFactory CreateBookPhone();
}

抽象产品:

public interface Book {void showDetail();
}
public interface Phone {void showDetail();
}

具体工厂:

//AppleFactory
public class AppleFactory implements AbstractFactory{@Overridepublic PhoneFactory CreateApplePhone() {return new Iphone15Phone();}@Overridepublic BookFactory CreateBookPhone() {return new  M3ProBook();}
}
//AppleFactory
public class HuaWeiFactory implements AbstractFactory{@Overridepublic Phone CreateApplePhone() {return new HuaWeiP60Phone();}@Overridepublic Book CreateBookPhone() {return new  MateBookXProBook();}
}

具体产品:

//Phone
public class HuaWeiP60Phone implements Phone {@Overridepublic void showDetail() {System.out.println("这是华为P60手机。");}
}public class Iphone15Phone implements Phone {@Overridepublic void showDetail() {System.out.println("这是苹果15手机。");}
}//Book
public class MateBookXProBook implements Book {@Overridepublic void showDetail() {System.out.println("这是华为MateBook X Pro笔记本。");}
}public class M3ProBook implements Book {@Overridepublic void showDetail() {System.out.println("这MacBook Pro M3 Pro笔记本电脑。");}
}

测试:

public class client {public static void main(String[] args) {HuaWeiFactory huaWeiFactory = new HuaWeiFactory();huaWeiFactory.CreateApplePhone().showDetail();huaWeiFactory.CreateBookPhone().showDetail();System.out.println("===========================");AppleFactory appleFactory = new AppleFactory();appleFactory.CreateApplePhone().showDetail();appleFactory.CreateBookPhone().showDetail();}
}/*
这是华为P60手机。
这是华为MateBook X Pro笔记本。
===========================
这是苹果15手机。
这MacBook Pro M3 Pro笔记本电脑。
*/

3、抽象工厂模式使用场景

  • 系统独立于产品创建、组合和表示:当系统需要独立于它的产品的创建、组合和表示时,可以使用抽象工厂模式。
  • 多个产品系列配置:如果系统需要由多个产品系列中的一个来配置,那么抽象工厂模式可以很好地满足这个需求。
  • 强调产品对象联合使用:当需要强调一系列相关的产品对象的设计以便进行联合使用时,抽象工厂模式非常适用。
  • 只想显示产品接口:如果只想提供一个产品类库,而只想显示它们的接口而不是实现时,抽象工厂模式是一个很好的选择。

4、抽象工厂模式总结

优点

  1. 封装性:抽象工厂模式将一组具有共同主题的单个工厂封装在一起,客户端只需要知道抽象工厂和产品族的抽象类型,而无需关心具体的实现细节。

  2. 产品族内的约束:抽象工厂模式有助于确保产品族内对象之间的兼容性。由于一个具体工厂负责创建一组产品,因此这组产品之间能够相互协作。

  3. 易于交换产品族:客户端代码只需与抽象工厂接口交互,因此可以轻松地更改产品族,而无需修改客户端代码。

  4. 可扩展性:当需要添加新的产品族时,只需添加新的具体工厂类,并在其中实现新的产品创建逻辑,而无需修改已有的代码。

  5. 降低耦合度:通过抽象工厂模式,客户端代码与具体产品类之间的耦合度被降低了,因为客户端代码只与抽象工厂接口交互。

缺点

  1. 难以支持新种类的产品:抽象工厂模式难以支持增加新的产品种类,因为每增加一个新的产品种类,就需要修改抽象工厂接口以及所有具体工厂类,这可能会违反开闭原则(对扩展开放,对修改关闭)。

  2. 系统复杂性增加:抽象工厂模式增加了系统的抽象性和复杂性,因为需要定义更多的接口和类。这可能会使得系统的理解和维护变得更加困难。

  3. 难以维护:如果产品族中的产品数量过多,或者产品之间的关联关系复杂,那么抽象工厂模式的实现和维护可能会变得非常困难。

  4. 客户端可能需要知道太多:在某些情况下,客户端可能需要知道抽象工厂的具体类型,以便能够创建正确的产品族。这可能会增加客户端代码的复杂性。

  5. 可能导致代码冗余:如果不同的产品族之间存在许多相似的产品,那么可能会导致在多个具体工厂类中出现相似的代码,从而产生代码冗余。


总结

好了,工厂模式就介绍到这里,我们下期见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/6315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux——命名管道

管道特点 只能用于具有具体祖先的进程之间的通信,通常,一个管道由一个进程创建,然后该进程调用fork,创建子进程,关闭相应的读写端,然后父子进程就可以通信了管道提供流式服务一般而言,进程退出…

一个肉夹馍思考的零耦合设计

刷抖音听说知识付费是普通人的一个收入增长点,写了三十几篇文章一毛钱没赚,感觉有点沮丧。天上下着小雨雨,稀稀嗦嗦的,由于了很久还是买了一个🤨。 忽然觉得生活有点悲催,现在已经变得斤斤计较,…

Android by viewModels()

在Android中,您可以使用ViewModel来管理UI相关的数据,而不会在配置更改(如旋转屏幕)后丢失数据。by viewModels()是一个Kotlin扩展函数,它允许您以类型安全的方式从Fragment或Activity中获取ViewModel实例。 以下是如…

Java里面的异常

Java里面的异常 父类: Exception 异常分为两类: 编译时异常:没有继承RuntimeException的异常,直接继承于Exception,编译阶段就会错误提示(用来提示程序员) 运行时异常:RuntimeException本身和子类,编译阶段没有错误提示,运行时出现的 可以写多个catch,如果存在父子关系,父要…

Modelsim自动仿真平台的搭建

Modelsim自动仿真平台的搭建 如果要搭建自动仿真平台脚本那就需要更改下面3个文件。run_simulation.bat、complie.do和wave.do文件。注:前提是安装了modulsim并且配置好了环境变量,这里不过多介绍。 一、下面是run_simulation.bat文件的内容 : 注释的…

四足机器人摆线规划程序

一、标准摆线公式 { x r ∗ ( θ − sin ⁡ ( θ ) ) y r ∗ ( 1 − cos ⁡ ( θ ) ) \left\{\begin{array}{l} xr *(\theta-\sin (\theta)) \\ yr *(1-\cos (\theta)) \end{array}\right. {xr∗(θ−sin(θ))yr∗(1−cos(θ))​ 这里的r表示摆线的圆的半径, θ \…

3:容器之分类和各种测试

文章目录 array测试array容器bsearch之前用qsort 可以极大提高搜索效率 测试vector容器list容器forward_list容器测试slistdeque容器stack容器quque为什么stack 和 queue这样的容器 没有迭代器的相关内容 multiset代码里面有使用 stl自带的find 和 容器自带的find 一般容器自带…

计算机视觉科普到实践

第一部分:计算机视觉基础 引言: 计算机视觉作为人工智能领域的一个重要分支,近年来取得了显著的进展。本文将带领读者深入了解计算机视觉的基础知识,并通过实践案例展示其应用。让我们一同探索这个令人着迷的领域吧!…

docker compose mysql主从复制及orchestrator高可用使用

1.orchestrator 功能演示: 1.1 多级级联: 1.2 主从切换: 切换成功后,原来的主库是红色的,需要在主库的配置页面点击“start replication ”,重新连接上新的主库。 1.3 主从故障,从库自动切换新…

高精度(加减乘除)

1.加法 我们第一位存低位&#xff08;倒着存方便&#xff09; 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace std; const int N1e610; vector<int> add(vector<int> &A,vector<int> &B) {vector<int> c;int t0;for…

【JVM】从硬件层面和应用层面的有序性和可见性,到Java的volatile和synchronized

Java的关键字volatile保证了有序性和可见性&#xff0c;这里我试着从底层开始讲一下有序性和可见性。 一&#xff0c;一致性 数据如果同时被两个cpu读取了&#xff0c;如何保证数据的一致性&#xff1f;或者换句话说&#xff0c;cpu1改了数据&#xff0c;cpu2的数据就成了无效…

python在Django中切换语言,中英文两种语言怎样切换

在Django中切换语言(比如中英文两种语言)通常涉及以下步骤: 设置语言和本地化 在你的Django项目的settings.py文件中,你需要设置LANGUAGES和LOCALE_PATHS。LANGUAGES是一个包含所有可用语言和它们的本地化的元组列表,而LOCALE_PATHS是包含.mo翻译文件路径的列表。 pyth…

LeetCode 题目 94:五种算法递归|迭代|莫里斯|线索二叉树|栈的迭代二叉树 实现中序遍历

本文详细探讨了五种二叉树中序遍历算法&#xff0c;包括递归、迭代、莫里斯遍历、线索二叉树和栈的迭代&#xff0c;评估了它们的效率和实用性。 题目描述 给定一个二叉树的根节点 root&#xff0c;返回它的中序遍历。 输入格式 root&#xff1a;二叉树的根节点。 输出格式…

基于AT89C52单片机的智能热水器控制系统

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/89242443?spm1001.2014.3001.5503 C 源码仿真图毕业设计实物制作步骤05 题 目 基于单片机的智能热水器系统 学 院 专 业 班 级 学 号 学生姓名 指导教师 完成日期…

242 基于matlab的3D路径规划

基于matlab的3D路径规划&#xff0c;蚁群算法&#xff08;ACO&#xff09;和天牛须&#xff08;BAS&#xff09;以及两种结合的三种优化方式&#xff0c;对3D路径规划的最短路径进行寻优。程序已调通&#xff0c;可直接运行。 242 3D路径规划 蚁群算法和天牛须 - 小红书 (xiaoh…

ant-design中的穿梭框提示文字修改

ant-design中的穿梭框提示文字修改 1.ant-design中的穿梭框提示文字修改 <a-transferv-model:target-keys"targetKeys":data-source"transform.list":filter-option"filterOption":list-style"{width: 100%,height: 500px,}":rowK…

ES6类与面向对象编程

ES6类与面向对象编程 ES6&#xff08;ECMAScript 6&#xff09;引入了类的概念&#xff0c;使得面向对象编程更加简洁和直观。ES6的类可以通过class关键词定义&#xff0c;类中可以定义构造函数、属性和方法。 以下是一个使用ES6类来定义一个简单的“人”类的示例&#xff1a…

unity入门学习笔记

文章目录 unity学习笔记熟悉界面窗口页面快捷键视图特点移动、旋转、缩放快捷键聚焦和隐藏 一些基本概念模型模型的导入一些补充 资源文件资源包的导出资源包的导入 轴心物体的父子关系空物体Global与localpivot与center 组件脚本基础我的第一个脚本 获取脚本组件本地坐标播放模…

Python基础学习之os模块

在Python编程的世界中&#xff0c;内置库为我们提供了丰富的功能和工具&#xff0c;使我们能够轻松处理各种任务。其中&#xff0c;os模块是一个极其重要且常用的库&#xff0c;它提供了与操作系统交互的接口。本文将带您一起探索os模块的一些常用功能。 1. os模块简介 os模块…

顶顶顶顶顶顶顶顶顶顶顶顶

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…