工厂模式 详解 设计模式

工厂模式

其主要目的是封装对象的创建过程,使客户端代码和具体的对象实现解耦。这样子就不用每次都new对象,更换对象的话,所有new对象的地方也要修改,违背了开闭原则(对扩展开放,对修改关闭)。使用工厂来生产对象,更换对象也直接在工厂更换即可。

工厂模式的主要好处包括:

  1. 解耦合:工厂模式将对象的创建过程与客户端代码分离,客户端不需要知道具体的对象是如何创建的,只需要通过工厂方法获取对象即可,从而降低了代码之间的耦合度。
  2. 灵活性:由于工厂负责创建对象,客户端可以通过工厂方法获取不同的对象实例,而无需关心具体的实现细节,从而提高了系统的灵活性。
  3. 可扩展性:如果需要添加新的产品类型,只需在工厂中添加相应的产品创建逻辑,而不需要修改客户端代码,这样可以很方便地扩展系统的功能。
  4. 统一管理:工厂模式将对象的创建集中在一个地方,便于统一管理和维护,提高了代码的可维护性。

使用场景:

  • 当一个系统需要创建多个类型的对象,并且这些对象之间存在着共同的接口时,可以考虑使用工厂模式。
  • 当客户端不需要知道具体的对象是如何创建的,只需要获取对象实例时,可以使用工厂模式。
  • 当系统需要动态地决定创建哪种类型的对象时,可以使用工厂模式。

工厂模式包含以下几个核心角色:

  • 抽象产品(Abstract Product):**定义了产品的共同接口或抽象类。**它可以是具体产品类的父类或接口,规定了产品对象的共同方法
  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象

这里介绍三种工厂

  • 简单工厂模式(不属于GOF的23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式

简单工厂模式

简单工厂不是一种设计模式,反而比较像是一种编程习惯。

结构:

简单工厂包含如下角色:

  • 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品 :实现或者继承抽象产品的子类
  • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。

使用场景

  • 当对象的创建逻辑相对简单,并且不需要频繁地进行变更时,可以考虑使用简单工厂模式。
  • 在客户端只知道所需产品的名称或类型,而不需要关心产品的创建过程时,可以使用简单工厂模式。

实现思路:

在这里插入图片描述

// 抽象产品接口
interface Product {      void show();
}// 具体产品类A
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("This is product A.");}
}// 具体产品类B
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("This is product B.");}
}// 简单工厂类
class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();}return null;}
}// 客户端
public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.show();Product productB = SimpleFactory.createProduct("B");productB.show();}
}

上面的工厂类创建对象的功能定义为静态的,这个属于是静态工厂模式,当然你也可以不设置为静态的。

优缺点:

优点:

  • 简单工厂模式中,客户端通过工厂类的静态方法来获取产品实例,而不需要直接实例化具体产品类。如果要实现新产品直接修改工厂类,而不需要在原代码中修改。

缺点:

  • 工厂类负责创建所有产品,因此如果系统需要添加新的产品类型,需要修改工厂类,违反了开放封闭原则。

工厂方法模式

使用工厂方法模式可以完美的解决简单工厂模式的缺点,完全遵循开闭原则。

概念

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。

结构

工厂方法模式的主要角色:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

图例

使用工厂方法模式对上例进行改进:
在这里插入图片描述

工厂方法模式适用于需要创建一系列相关对象的情况

// 抽象产品接口
interface Product {void show();
}// 具体产品类A
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("This is product A.");}
}// 具体产品类B
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("This is product B.");}
}// 抽象工厂类
interface Factory {Product createProduct();
}// 具体工厂类A,负责创建产品A
class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 具体工厂类B,负责创建产品B
class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}// 客户端
public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.show();Factory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.show();}
}

于是乎要增加产品类时只要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点。

使用场景

  • 当需要创建的对象是一个具体的产品,但是不确定具体产品的类型时,可以使用工厂方法模式。
  • 在工厂类中定义一个创建产品的抽象方法,由子类负责实现具体产品的创建过程,从而实现了产品的创建和客户端的解耦

优缺点

优点:

  • 工厂方法模式中,客户端通过调用工厂类的方法来创建产品,具体产品的创建逻辑由子类实现,不同的产品由不同的工厂子类负责创建。
  • 工厂方法模式符合开放封闭原则,因为客户端可以通过新增工厂子类来添加新的产品类型,而无需修改原有的代码。

缺点:

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

抽象工厂模式

抽象工厂模式通常涉及一族相关的产品,每个具体工厂类负责创建该族中的具体产品。

使用场景

  • 当一个系统需要创建一系列相互关联或相互依赖的产品对象时,可以考虑使用抽象工厂模式。
  • 抽象工厂模式提供了一个创建一组相关或相互依赖对象的接口,客户端可以通过该接口来创建产品族中的不同产品,而不需要关心具体的产品实现。

所以由此也可看出,普通工厂模式,工厂方法模式都只是单一产品类的工厂;而很多时候我们需要综合性的,需要生产多等级产品的工厂。下图所示横轴是产品等级,也就是同一类产品;纵轴是产品族,也就是同一品牌的产品,同一品牌的产品产自同一个工厂:

在这里插入图片描述

结构

抽象工厂模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

请添加图片描述

代码案例:

// 抽象产品接口
interface Product {void show();
}// 具体产品类A
class ConcreteProductA implements Product {@Overridepublic void show() {System.out.println("This is product A.");}
}// 具体产品类B
class ConcreteProductB implements Product {@Overridepublic void show() {System.out.println("This is product B.");}
}// 抽象工厂接口
interface AbstractFactory {Product createProductA();Product createProductB();
}// 具体工厂类,负责创建产品A和产品B
class ConcreteFactory implements AbstractFactory {@Overridepublic Product createProductA() {return new ConcreteProductA();}@Overridepublic Product createProductB() {return new ConcreteProductB();}
}// 客户端
public class Client {public static void main(String[] args) {AbstractFactory factory = new ConcreteFactory();Product productA = factory.createProductA();productA.show();Product productB = factory.createProductB();productB.show();}
}
  • 使用场景

    • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
    • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
    • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

优缺点

优点:

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

缺点:

当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

模式扩展 (利用反射机制来创建对象)

简单工厂+配置文件解除耦合

可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。

通过使用配置文件,将创建对象的参数存储在外部配置文件中,可以在不修改客户端代码的情况下,通过修改配置文件来改变对象的创建方式。这样就可以实现对创建逻辑的解耦合,客户端不需要知道具体的创建方式,只需要从工厂类获取对象即可。

具体实现步骤如下:

  1. 在配置文件中配置需要创建的对象的类名或者类型。
  2. 在简单工厂类中读取配置文件,并根据配置的信息来创建对应的对象。

假设有一个配置文件 config.properties,内容如下:

product.type=ConcreteProductA

创建简单工厂类 SimpleFactory.java,用于读取配置文件并根据配置创建对象:

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;public class SimpleFactory { public static Product createProduct() {Properties properties = new Properties();try (InputStream inputStream = SimpleFactory.class.getResourceAsStream("config.properties")) {properties.load(inputStream);String productType = properties.getProperty("product.type");if ("ConcreteProductA".equals(productType)) {return new ConcreteProductA();} else if ("ConcreteProductB".equals(productType)) {return new ConcreteProductB();}} catch (IOException e) {e.printStackTrace();}return null;}
}

在日常开发中,设计模式中的一些常用模式包括:

  1. 单例模式 (Singleton):用于确保一个类只有一个实例,并提供全局访问点,例如数据库连接池、日志系统等。
  2. 工厂模式 (Factory):用于创建对象的接口,但是由子类决定要实例化的类是哪一个。例如,可以用工厂模式创建各种类型的文件解析器。
  3. 观察者模式 (Observer):用于建立对象之间一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知。例如,GUI界面中的事件监听器。
  4. 策略模式 (Strategy):定义一系列算法,将每个算法封装起来,并使它们可以互换。例如,根据用户的选择使用不同的支付策略。
  5. 装饰器模式 (Decorator):动态地给一个对象添加一些额外的职责。例如,在图像处理中可以使用装饰器来添加滤镜效果。
  6. 模板方法模式 (Template Method):定义一个算法的骨架,允许子类为一个或多个步骤提供实现。例如,在构建流程中的各个阶段都有固定的步骤,但是具体实现可能不同。

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

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

相关文章

win中删除不掉的文件,火绒粉碎删除亲测有效

看网上的 win R 然后终端输入什么删除的,照做了都没有删掉 有火绒的可以试试: 拖进去就删掉了 很好使

选项 打光 试题总结

试题1 被测物体100100mm,精度要求被测物体 ,精度要求0.1mm,相机距被测物体在200~320mm之间,要求选择合适的相机和镜头? 分析如下: 通常我们用的相机靶面是4:3 的所以我们要用短边来计算视场&am…

Jmeter系列(5)线程数到底能设置多大

疑惑 一台设备的线程数到底可以设置多大? 线程数设置 经过一番搜索找到了这样的答案: Linux下,2g的 java内存,1m 的栈空间,最大启动线程数2000线程数建议不超过1000jmeter 能启动多少线程,由你的堆内存…

Tomcat 下部署若依单体应用可观测最佳实践

实现目标 采集指标信息采集链路信息采集日志信息采集 RUM 信息会话重放 即用户访问前端的一系列过程的会话录制信息,包括点击某个按钮、操作界面、停留时间等,有助于客户真是意图、操作复现 版本信息 Tomcat (9.0.81)Springboot(2.6.2)JDK (>8)DDT…

ensp路由器将不同网络连通在一起

1.拓扑结构信息如下 二层交换机:lsw2,lsw3,lsw5,lsw6 不进行ip配置,只是定义vlan,和主机标注的保持一致,向下连接pc用access,向上连接路由交换机用trunk lsw2配置信息如下图 定义vlan,设置各个连接口的方式…

tcpdump 常用用法

简要记录下tcpdump用法 监控某个ip上的某个端口的流量 tcpdump -i enp0s25 tcp port 5432 -nn -S 各个参数作用 -i enp0s25 指定抓包的网卡是enp0s25 -nn 显示ip地址和数字端口 ,如果只 -n 则显示ip,但是端口为services文件中的服务名 如果一个…

用python写一个自动化部署工具

效果 起因 现在springboot项目的自动化部署已经非常普遍,有用Jenkins的,有用git钩子函数的,有用docker的…等等。这段时间在玩python,想着用python实现自动化部署,即能锻炼下编码能力,又方便运维。于是开始…

每日学习总结20240228

每日总结 20240228 1.获取系统命令执行结果 #include <stdio.h>#define TRUE 1 #define FALSE 0int get_system_cmd_result(const char *command, char *buffer, int bufferLen) {FILE *pipe popen(command, "r");if (pipe NULL) {return FALSE;}while (f…

HTML-表格、表单和CSS初识,选择器,书写规范

&#xff11;. 表格标签 &#xff11;.&#xff11;创建表格 表格标签是一种用来处理&#xff0c;显示表格式数据的常用标签。 注意&#xff1a; &#xff11;. tr 用于定义表格中的一行&#xff0c;必须嵌套在 table标签中&#xff0c;在 table中包含几对 tr&#xff0c;就有…

实用指南:SOLIDWORKS数据失真问题的解决之道

在数据处理和模拟计算的过程中&#xff0c;数据失真是一个常见的挑战。数据失真指的是由于计算机或人为操作导致的原始数据与计算结果或实际情况之间的偏差。特别是在使用SOLIDWORKS这类工程设计软件时&#xff0c;数据失真可能由多种因素引起&#xff0c;如软件版本老旧、设置…

AI大模型-启航

文章目录 什么是大模型&#xff1f;&#xff08;大体现在参数量巨大&#xff09;大模型将会改变那些行业&#xff08;大模型有哪些作用&#xff1f;&#xff09;如何搞数据训练模型&#xff1f;LangChain带来的技术变革LangChain架构 什么是大模型&#xff1f;&#xff08;大体…

Vue+SpringBoot打造不良邮件过滤系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统用户模块2.2 收件箱模块2.3 发件箱模块2.4 垃圾箱模块2.5 回收站模块2.6 邮箱过滤设置模块 三、实体类设计3.1 系统用户3.2 邮件3.3 其他实体 四、系统展示五、核心代码5.1 查询收件箱档案5.2 查询回收站档案5.3 新…

图像分割 - 查找图像的轮廓(cv2.findContours函数)

1、前言 轮廓,是指图像中或者物体的外边缘线条。在简单的几何图形中,图形的轮廓是由平滑的线条构成,容易被识别。但不规则的图形或者生活中常见的物体轮廓复杂,识别起来比较困难 2、findContours函数 这里先介绍函数的参数,具体的含义会在下面实验中阐述 opencv 提供的轮…

React入门之React_渲染基础用法和class实例写法

渲染元素 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>04元素渲染</title><script src&…

2024-2-29-网络编程作业

1>TCP 源代码: 服务器端&#xff1a; #include <myhead.h> #define SER_IP "10.168.1.111" #define SER_PORT 8888 #define MAXSIZE 128 int main(int argc, char const *argv[]) {int sfd socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in sin;sin…

RDD简介与基础编程

1. 什么是RDD&#xff1f; RDD&#xff08;Resilient Distributed Dataset&#xff09;叫做弹性分布式数据集&#xff0c;是Spark中最基本的数据处理模型。在代码中&#xff0c;RDD是一个抽象类&#xff0c;他代表着一个弹性的、不可变的、可分区的、里面的元素可并行计算的集…

android TextView 实现富文本显示

android TextView 实现富文本显示&#xff0c;实现抖音直播间公屏消息案例 使用&#xff1a; val tvContent: TextView helper.getView(R.id.tvContent)//自己根据UI业务要求&#xff0c;可以控制 图标显示 大小val levelLabel MyImgLabel( bitmap 自己业务上的bitmap )va…

第零章_计算机导论

0.1 计算机&#xff1a;辅助人脑的好工具 所谓的计算机就是一种计算器&#xff0c;而计算器其实是:『接受用户输入指令与数据&#xff0c;经由中央处理器的数学与逻辑单元运算处理后&#xff0c;以产生或储存成有用的信息』。因此&#xff0c;只要有输入设备(不管是键盘还是触摸…

HTML5:七天学会基础动画网页4

backgorund-size 值与说明 length(单位像素):设置背景图片高度和宽度&#xff0c;第一个值设置宽度&#xff0c;第二个值设置高度&#xff0c;如果只给出一个值&#xff0c;第二个是设置为auto。 percentage(百分比):以父元素的百分比来设置背景图像的宽度和高度&#xff0c…

CSS技巧:实现两个div在同一行显示的方法

css如何让两个div在同一行显示 - web开发 - 亿速云 在Web开发中&#xff0c;经常遇到需要将多个元素水平排列在同一行的情况。其中一个常见的需求是将两个div元素放置在同一行上&#xff0c;使它们并排显示。在本文中&#xff0c;我们将介绍几种实现这一效果的CSS方法。 1. 使…