设计模式之工厂模式

news2025/2/26 14:49:30

文章目录

  • 1.前言
    • 工厂模式的三种实现方式
    • 应用场景
  • 2.简单工厂模式
    • 核心组成
    • 实现
    • UML类图
    • 优点与缺点
  • 3.工厂方法模式
    • 核心组成
    • 实现
    • UML类图
    • 优点与缺点
  • 4.抽象工厂模式
    • 核心组成
    • 实现
    • UML类图
    • 优点与缺点

1.前言

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

  • 举个例子来说,就是一个电脑生产厂,它可以生产型号A、型号B和型号C。

工厂模式的三种实现方式

  • 简单工厂模式:通过传入相应的类型来返回对应的产品类,这种方式比较单一,可拓展性比较差
  • 工厂方法模式:通过具体的工厂类实现相应的方法返回相应的产品类,这种方式可拓展性比较强
  • 抽象工厂模式:基于上述两种模式的拓展,且⽀持细化产品

应用场景

  • 解耦合:把对象的创建和使用的过程分开。就是Class A 想调用 Class B ,那么A只是调用B的方法,而至于B的实例化,就交给工厂类。
  • 复用代码降低代码重复:如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的创建过程的修改维护。

2.简单工厂模式

核心组成

  • Factory:工厂类,简单工厂模式的核心,包含了所有创建实例的内部逻辑
  • IProduct:抽象产品类,简单工厂模式创建所有产品类的父类,描述所有实例所共有的公共接口
  • Product:具体产品类,是简单工厂创建的目标

实现

实现分为三步:

  1. 创建抽象产品类,具体的业务逻辑由具体产品类实现
  2. 创建具体产品类,继承抽象产品类,事项具体的业务
  3. 创建工厂类,实现获取产品类的方法,方法会根据传入的参数去生成具体的产品类

抽象产品类

public interface ICalculation {
    int getResult(int num1, int num2);
}

具体产品类

public class CalculationSubtract implements ICalculation {
    @Override
    public int getResult(int num1, int num2) {
        return num1 - num2;
    }
}


public class CalculationMultiply implements ICalculation {
    @Override
    public int getResult(int num1, int num2) {
        return num1 * num2;
    }
}


public class CalculationAdd implements ICalculation {
    @Override
    public int getResult(int num1, int num2) {
        return num1 + num2;
    }
}

工厂类

public class SimpleCalculationFactory {

    public ICalculation createCalculation(String operation){
        switch (operation){
            case "+":
                return new CalculationAdd();
            case "-":
                return new CalculationSubtract();
            case "*":
                return new CalculationMultiply();
            default:
                return null;
        }
    }
}

测试类

public class SimpleCalculationTest {
    public static void main(String[] args) {
        SimpleCalculationFactory simpleCalculationFactory = new SimpleCalculationFactory();
        ICalculation calculation = simpleCalculationFactory.createCalculation("+");
        int result = calculation.getResult(1, 2);
        System.out.println(result);
    }
}

UML类图

请添加图片描述

优点与缺点

优点

  • 将对象的创建和对象本身的业务处理分离可以降低系统的耦合度,使两者修改起来比较容易。

缺点

  • 工厂类的职责过重,增加新的产品就需要修改工厂类的逻辑判断,这违反了开闭原则(软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭)。

3.工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法把实例化推迟到子类。这样的好处是再添加新的对象的时候,就不用再改代码了,代码的可扩展性强了。要做的就是:子类工厂继承或实现抽象的工厂,写一个新的创建类的工厂,然后再在客户端调用即可,不需要修改原来的代码。

核心组成

  • IProduct:抽象产品接口,描述所有实例所共有的公共接⼝
  • Product:具体产品类,实现抽象产品类的接⼝,⼯⼚类创建对象,如果有多个需要定义多个
  • IFactory:抽象⼯⼚接口,描述具体⼯⼚的公共接⼝
  • Factory:具体⼯⼚类,实现创建产品类对象,实现抽 象⼯⼚类的接⼝,如果有多个需要定义多个

实现

实现分为四步:

  1. 创建抽象产品类,具体的业务逻辑由具体产品类实现
  2. 创建具体产品类,继承抽象产品类,事项具体的业务
  3. 创建抽象工厂类,描述具体工厂
  4. 创建工厂类,实现获取产品类的方法,方法会根据传入的参数去生成具体的产品类

这里抽象产品类以及具体产品类与简单工厂中的实现相同这里就不再做展示

我们直接展示抽象工厂类和具体工厂类。

抽象工厂类

public interface IFactory {
    ICalculation createCalculation();
}

具体工厂类

public class AddFactory implements IFactory{
    @Override
    public ICalculation createCalculation() {
        return new CalculationAdd();
    }
}

public class MultiplyFactory implements IFactory{
    @Override
    public ICalculation createCalculation() {
        return new CalculationMultiply();
    }
}

public class SubtractFactory implements IFactory{
    @Override
    public ICalculation createCalculation() {
        return new CalculationSubtract();
    }
}

测试代码

public class FactoryMethodTest {
    public static void main(String[] args) {
        IFactory addFactory = new AddFactory();
        ICalculation calculation = addFactory.createCalculation();
        int result = calculation.getResult(1, 2);
        System.out.println(result);
    }
}

UML类图

请添加图片描述

优点与缺点

优点

  • 符合开闭原则,增加⼀个产品类,只需要实现其他具体的产品类和具体的⼯⼚类;
  • 符合单⼀职责原则,每个⼯⼚只负责⽣产对应的产品;
  • 使⽤者只需要知道产品的抽象类,⽆须关⼼其他实现类,满⾜迪⽶特法则依赖倒置原则⾥⽒替换原则
    • 迪⽶特法则:最少知道原则,实体应当尽量少地与 其他实体之间发⽣相互作⽤;
    • 依赖倒置原则:针对接⼝编程,依赖于抽象⽽不依赖于具体;
    • ⾥⽒替换原则:俗称LSP,任何基类可以出现的地⽅,⼦类⼀定可以出现, 对实现抽象化的具体步骤的规范;

缺点

  • 增加⼀个产品,需要实现对应的具体⼯⼚类和具体产品类;
  • 每个产品需要有对应的具体⼯⼚和具体产品类;

4.抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体定。抽象工厂允许客户使用抽象确有工厂创建一组相关的产品,而不需要(或关心)实际产出的具体产品是什么。这样一样,客户就从具体的产品中被解耦。

在前面的工厂方法模式中,考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机。工厂方法模式只考虑生产同等级(同种类被称为同等级)的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调。而抽象工厂模式就考虑了多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,如图所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。

请添加图片描述

核心组成

  • IFactory:抽象工厂类,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口。
  • ConcreteFactory:具体工厂类,用于生产不同产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象。
  • IProduct:抽象产品类,这是一个产品家族,每一个具体工厂都能够生产一整组产品。
  • Product:具体产品类

实现

这里拿Haier和TCL的电器作为例子来讲解抽象工厂模式。

抽象工厂类

public interface IFactory {
    IAirCondition createAirCondition();
    ITelevision createTelevision();
}

具体工厂类

public class HaierFactory implements IFactory{
    @Override
    public IAirCondition createAirCondition() {
        return new HaierAirCondition();
    }

    @Override
    public ITelevision createTelevision() {
        return new HaierTelevision();
    }
}

public class TCLFactory implements IFactory{
    @Override
    public IAirCondition createAirCondition() {
        return new TCLAirCondition();
    }

    @Override
    public ITelevision createTelevision() {
        return new TCLTelevision();
    }
}

抽象产品类

public interface ITelevision {
    void show();
}

public interface IAirCondition {
    void airConditioning();
}

具体产品类

public class HaierTelevision implements ITelevision{
    @Override
    public void show() {
        System.out.println("Haier电视启动了,显示效果偏暖......");
    }
}

public class HaierAirCondition implements IAirCondition{
    @Override
    public void airConditioning() {
        System.out.println("Haier空调启动了,温度开始变化......");
    }
}
public class TCLAirCondition implements IAirCondition{
    @Override
    public void airConditioning() {
        System.out.println("TCL空调启动了,温度开始变化......");
    }
}

public class TCLTelevision implements ITelevision{
    @Override
    public void show() {
        System.out.println("TCL电视启动了,显示效果偏冷......");
    }
}

UML类图

请添加图片描述

优点与缺点

优点

  • 当⼀个产品族中的多个对象被设计成⼀起⼯作时,它能 保证使⽤⽅始终只使⽤同⼀个产品族中的对象
  • 产品等级结构扩展容易,如果需要增加多⼀个产品等级,只需要增加新的⼯⼚类和产品类即可

缺点

  • 产品族扩展困难,要增加⼀个系列的某⼀产品,既要在 抽象的⼯⼚和抽象产品⾥修改代码,不是很符合开闭原 则
  • 增加了系统的抽象性和理解难度

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

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

相关文章

React - Ant Design4.x版本安装使用,并按需引入和自定义主题

React - Ant Design4.x版本安装使用,并按需引入和自定义主题一. 安装使用 antd二.antd 高级配置安装 craco,对 create-react-app 的默认配置进行自定义自定义主题安装 babel-plugin-import ,按需加载组件代码和样式Ant Design官网…

备赛笔记:RCNN网络基础

1 目标检测: 目标检测指的是对目标进行分类与定位,输入图片,输出物体类别以及其坐标 目标检测模型分为one stage 和two stage类型。one stage及端到端,速度较快,但是准确性较差,two stage网络速度较慢&…

CDH5.12.0-HiveServer2-java.net.SocketTimeoutException: Read timed out

问题描述 环境: 开发调度平台:数栖平台4.18(16000任务,7000工作流)大数据平台:CDH 5.12.0,大数据组件默认版本BI工具:FineBI实时数仓:Dolphinscheduler StarRocks 问…

从核酸检测平台崩盘看性能工程的范围

近几年疫情肆虐,健康码系统和核酸检测系统成了民生的保障。在疫情张狂的时候,这类系统的稳定性、可用性是关键的技术支撑能力。 每个地方的健康码平台都或多或少地出现过问题,影响每个人的生活。 从我工作十几年的性能工作经验,来…

225. 用队列实现栈-C语言

题目来源:力扣 题目描述: 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 实现 MyStack 类: void push(int x) 将元素 x 压…

Python爬取数据分析

一.python爬虫使用的模块 1.import requests 2.from bs4 import BeautifulSoup 3.pandas 数据分析高级接口模块 二. 爬取数据在第一个请求中时, 使用BeautifulSoup   import requests # 引用requests库 from bs4 import BeautifulSoup # 引用BeautifulSoup库 res_movies re…

pycharm Process finished with exit code: -1073741571

问题现象 在pycharm使用debug模式调试代码时,异常退出,且错误码为-1073741571。除了错误码外,并没有看到其它报错。 分析 查阅资料: Process finished with exit code -1073741571 (0xC00000FD) when trying to implement ab…

ZPM介绍(3)

建立私服(Porxy-Registry) 这张图解释了您的私服是怎么工作的, 整篇文章在这里: Proxy-Registry 搭建私服 您需要有一台自己的的服务器, 在上面安装IRIS, zpm, 然后用zpm去下载另一个软件包“zpm-registry"。象这样 zpm:DEMO>search …

如何设置子域名?

什么叫子域名 域名可以划分为各个子域,子域还可以继续划分为子域的子域,这样就形成了顶级域、主域名、子域名等。 举例: “.com”是顶级域名(一级域名); “aliyun.com”是主域名(二级域名&…

AtCoder Beginner Contest 264 G.String Fair(最短路/暴力dp 补写法)

题目 n(n<18278)个串&#xff0c;第i个串Ti(Ti为纯小写字母串且长度不超过3)&#xff0c; 得分Pi(-1e9<Pi<1e9)&#xff0c;表示只要子串中出现一次Ti&#xff0c;就会获得Pi的得分 对于你可以构造的无限长的串S来说&#xff0c;S的最终得分&#xff0c;为其中每一…

我参加第七届NVIDIA Sky Hackathon——训练CV模型

如何从0开始训练自己的CV模型 第一步 配置基本环境(在上一篇已经配置了我参加第七届NVIDIA Sky Hackathon——训练ASR模型 ) 第二步 利用labelimg制作图像数据集 第三步 开始训练resnet18模型 文章目录如何从0开始训练自己的CV模型前言一、利用labelimg制作图像数据集1.安装la…

JetPack之LifeCycle设计模式与解耦艺术的极致运用

在研发过程中&#xff0c;解耦是一个永恒的话题。因为解耦可以为后续的维护、功能添加、防内存泄漏、问题查找及更新都带来便利且做到影响最小&#xff0c;但如何进行解耦设计却是一门艺术。今天&#xff0c;我们就来看看google工程师是如何设计LifeCycle的。 我们在很多时候都…

【故障诊断分析】FFT轴承故障诊断(包络谱)【含Matlab源码 2002期】

⛄一、轴承故障分析简介 1 研究背景 滚动轴承故障占旋转机械故障的大约30%&#xff0c;现阶段主要采用信号分析来进行故障识别。探究形成机械设备故障尤其是滚动轴承的理论和诊断手段及方法是广大科学家们共同追求的目标&#xff0c;无论是在工程实际还是故障分析理论上都有着…

cat命令应用

记录&#xff1a;338 场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;使用cat命令查看文件内容&#xff1b;把内容输出到指定文件&#xff1b;把多个文件合并为一个文件等。比如查看Tomcat的日志文件等。 版本&#xff1a; 操作系统&#xff1a;CentOS 7.9 1.命令应用…

Kafka - 06 Kafka 集群环境搭建(三台虚拟机)

文章目录1. 克隆虚拟机2. Zookeeper 集群搭建3. Kafka 集群搭建4. 测试消息发送和消费1. 主题操作2. 生产者生产消息3. 消费者消费消息1. 克隆虚拟机 kafka集群搭建&#xff0c;需要3台虚拟机环境&#xff0c;但是我目前只安装了一台虚拟机&#xff0c;因此还需要准备两台虚拟…

SpringBoot SpringBoot 原理篇 2 自定义starter 2.5 使用属性配置设置功能参数【2】

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇2 自定义starter2.5 使用属性配置设置功能参数【2】2.5.1 直接开干2.5.2 小结…

【网络篇】第十八篇——ping的工作原理

目录 IP协议助手——ICMP协议 查询报文类型 差错报文类型 网络不可达代码为0 主机不可达代码为1 协议不可达代码为2 端口不可达代码为3 需要进行分片但设置不分片位片码为4 ping——查询报文类型使用 traceroute IP协议助手——ICMP协议 ping是基于ICMP协议工作的&a…

解决Redis Object Cache Pro插件无法使用高性能配置的解决方案

说明 辉哥演示站和本地使用的对象缓存都是redis&#xff0c;刚好手上有Redis Object Cache Pro插件&#xff0c;目前大多数用户都是用的是官方推荐的基础配置&#xff0c;并没有使用高性能配置&#xff08;官方的说法是在毫秒内优化高流量站点&#xff09;&#xff0c;刚好辉哥…

java项目_第163期ssm药品电子商城系统_java毕业设计

java项目_第163期ssm药品电子商城系统_java毕业设计 今天分享的项目是《ssm药品电子商城系统》 该项目分为3个角色&#xff0c;管理员、用户、医生。 1、用户可以浏览前台,购买药品&#xff0c;并将药品加入到购物车&#xff1b; 用户还可以浏览医生信息&#xff0c;进行在线预…

《Java开发手册》三-代码风格

前言 这第三章主要是讲一些代码风格和规范&#xff0c;代码风格不影响程序运行&#xff0c;但对于团队的合作开发效率十分重要&#xff0c;相对前两章&#xff0c;这章内容较少 命名规约 命名符合本语言特性 每种语言都有自己的特殊风格&#xff0c;比如java不能以下划线&am…