设计模式学习(二)工厂模式——抽象工厂模式

news2024/11/14 4:28:57

设计模式学习(二)工厂模式——抽象工厂模式

  • 背景
  • 抽象工厂模式
  • 优点与缺点
  • 参考文章

背景

现在我需要开发一个相机操作模块,它可能在Windows下运行,也可能在Linux下运行。由于在厂家提供的SDK中,Windows下的SDK和Linux下的SDK是有区别的,因此对于一个品牌的相机,我们要创建两个类去封装这两个不同平台下的API。

我们先使用工厂方法模式去设计(以Basler相机为例),类图如下:
在这里插入图片描述

对应的代码(就不用智能指针了,要不然类图不好画):

class BaslerCamera
{
public:
    virtual ~BaslerCamera() = default;
    virtual bool OpenCamera() = 0;
};

class LinuxBaslerCamera : public BaslerCamera
{
public:
    ~LinuxBaslerCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};

class WindowsBaslerCamera : public BaslerCamera
{
public:
    ~WindowsBaslerCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};

class CameraFactory
{
public:
    virtual ~CameraFactory() = default;
    virtual BaslerCamera* CreateBaslerCamera() = 0;
};

class LinuxCameraFactory : public CameraFactory
{
public:
    BaslerCamera* CreateBaslerCamera() override
    {
        return new LinuxBaslerCamera();
    }
};

class WindowsCameraFactory : public CameraFactory
{
public:
    BaslerCamera* CreateBaslerCamera() override
    {
        return new WindowsBaslerCamera();
    }
};

//客户端
int main()
{
	//如果更换平台,客户端代码只需要修改这一处
    CameraFactory* cameraFactory = new LinuxCameraFactory();
    
    BaslerCamera* camera = cameraFactory->CreateBaslerCamera();
    
    camera->OpenCamera();
    
    return 0;
}

现在若新增了一个品牌的相机:Sick,那么按照工厂方法模式的设计思路,就会为其创建出对应的抽象工厂类和具体工厂类(具体代码略)。

但是进一步分析可以发现,对于这个模块,它要么在Windows下运行,要么在Linux下运行。即对于抽象产品BaslerCameraSickCamera,要么实例化LinuxBaslerCameraLinuxSickCamera,要么实例化WindowsBaslerCameraWindowsSickCamera

可以说不同的相机被划分在Linux相机和Window相机这两个产品族下,因此我们不需要为每一个品牌的相机都去实现一组对应的工厂类,而是只使用两个工厂WindowsCameraFactoryLinuxCameraFactory去管理各自对应平台下的相机的创建过程。

那么工厂类的代码就会变成这样:

class CameraFactory
{
public:
    virtual ~CameraFactory() = default;
    virtual BaslerCamera* CreateBaslerCamera() = 0;
    virtual SickCamera* CreateSickCamera() = 0;
};

class LinuxCameraFactory : public CameraFactory
{
public:
    BaslerCamera* CreateBaslerCamera() override
    {
        return new LinuxBaslerCamera();
    }

    SickCamera* CreateSickCamera() override
    {
        return new LinuxSickCamera();
    }
};

class WindowsCameraFactory : public CameraFactory
{
public:
    BaslerCamera* CreateBaslerCamera() override
    {
        return new WindowsBaslerCamera();
    }

    SickCamera* CreateSickCamera() override
    {
        return new WindowsSickCamera();
    }
};

这就引出了抽象工厂模式

抽象工厂模式

抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类

在这里插入图片描述
AbstractProductAAbstractProductB是两个抽象产品,之所以为抽象,是因为他们可能有多种不同的实现,就刚才的例子来说,抽象产品就是BaslerCameraSickCameraProductA1ProductA2ProductB1ProductB2就是对两个抽象产品的具体分类的实现,对应例子中的LinuxBaslerCameraWindowsBaslerCameraLinuxSickCameraWindowsSickCamera

AbstractFactory是一个抽象工厂基类,对应例子中的CameraFactory,它里面应该包含产品族中每个产品创建的抽象方法。ConcreteFactory1ConcreteFactory2是具体工厂,对应例子中的LinuxCameraFactoryWindowsCameraFactory

对于客户端,通常是在代码中创建一个具体工厂的实例(这个实例就对应着一个产品族),使用这个工厂实例再创建产品族内具体的产品对象。

客户端代码如下:

int main()
{
    /*
    若在windows平台,只需将本句改为:
    CameraFactory* cameraFactory = new WindowsCameraFactory();
    */
    CameraFactory* camera_factory = new LinuxCameraFactory();
    
    BaslerCamera* basler_camera = camera_factory->CreateBaslerCamera();
    basler_camera->OpenCamera();

    SickCamera* sick_camera = camera_factory->CreateSickCamera();
    sick_camera->OpenCamera();

    return 0;
}

完整代码如下:

class BaslerCamera
{
public:
    virtual ~BaslerCamera() = default;
    virtual bool OpenCamera() = 0;
};

class LinuxBaslerCamera : public BaslerCamera
{
public:
    ~LinuxBaslerCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};

class WindowsBaslerCamera : public BaslerCamera
{
public:
    ~WindowsBaslerCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};

class SickCamera
{
public:
    virtual ~SickCamera() = default;
    virtual bool OpenCamera() = 0;
};

class LinuxSickCamera : public SickCamera
{
public:
    ~LinuxSickCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};

class WindowsSickCamera : public SickCamera
{
public:
    ~WindowsSickCamera() override = default;
    bool OpenCamera() override
    {
        return true;
    }
};


class CameraFactory
{
public:
    virtual ~CameraFactory() = default;
    virtual BaslerCamera* CreateBaslerCamera() = 0;
    virtual SickCamera* CreateSickCamera() = 0;
};

class LinuxCameraFactory : public CameraFactory
{
public:
    BaslerCamera* CreateBaslerCamera() override
    {
        return new LinuxBaslerCamera();
    }

    SickCamera* CreateSickCamera() override
    {
        return new LinuxSickCamera();
    }
};

class WindowsCameraFactory : public CameraFactory
{
public:
    BaslerCamera* CreateBaslerCamera() override
    {
        return new WindowsBaslerCamera();
    }

    SickCamera* CreateSickCamera() override
    {
        return new WindowsSickCamera();
    }
};

int main()
{
    //若在windows平台,只需将本句改为CameraFactory* cameraFactory = new WindowsCameraFactory();
    CameraFactory* camera_factory = new LinuxCameraFactory();
    
    BaslerCamera* basler_camera = camera_factory->CreateBaslerCamera();
    basler_camera->OpenCamera();

    SickCamera* sick_camera = camera_factory->CreateSickCamera();
    sick_camera->OpenCamera();

    return 0;
}

优点与缺点

优点:

  • 易于交换产品族:工厂的实例化过程在一个客户端只需要出现一次,修改方便

缺点:

  • 提供方违反开闭原则:如果现在在每个产品族内新增一个品牌相机(如Huaray),那么除了要增加HuarayCameraWindowsHuarayCameraLinuxHuarayCamera三个产品类之外(这是必要的),还要修改CameraFactoryLinuxCameraFactoryWindowsCameraFactory这三个工厂类,违反了开闭原则。
  • 客户端违法开闭原则:客户端在开始的时候都要CameraFactory* camera_factory = new LinuxCameraFactory();,若是要更换为Windows平台,则还需手动修改实例化的类型,违反了开闭原则。而且如果客户端不止一个,则每一个客户端都需要手动修改,效率低。

对于抽象工厂模式的改进方法,将在下一篇文章中讨论。

参考文章

1.《大话设计模式》

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

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

相关文章

DROO论文笔记

推荐文章DROO源码及论文学习 读论文《Deep Reinforcement Learning for Online Computation Offloading in Wireless Powered Mobile-Edge Computing Networks》的笔记 论文地址:用于无线移动边缘计算网络在线计算卸载的深度强化学习 论文代码地址:DR…

统计学9——分类数据统计

知识结构 内容精读 1.分类数据与$\chi^2$统计量 分类数据在第一章已经进行了详细介绍,就是对数据进行分类的结果,特征是,调查结果虽然用数值表示,但不同数值描述了调查对象的不同特征。由此分类数据的结果是频数,而$…

git链接远程仓库

【 一 】ssh链接远程仓库 删除git仓库 【 1 】初步使用方法 1、之前把本地代码,以https形式,提交到了远程仓库 # - git remote add origin https://gitee.com/bai-zhitao/lufy.git- 输入用户名密码2、ssh认证,只需要配置一次&#xff…

uniapp踩坑之项目:uni-table垂直居中和水平居中

uni-table 中的水平居中uni-td align"center"&#xff0c;css里的属性vertical-align: middle //html 水平居中<uni-table ref"table" :loading"loading" border stripe emptyText"暂无更多数据"><uni-tr><uni-th :wid…

车载音视频MediaPlayer优化方案

媒体播放现状 从手机到车载&#xff0c;在很多地方还是有很大的不同。针对多媒体的场景Android车机目前大部分结构大致结构如下图&#xff1a; 从以上图看出的问题&#xff1a; 各个音视频APP单独实现播控界面&#xff0c;播放链路不一致&#xff0c;使用的底层播放器和音频焦…

JavaEE:Spring Web简单小项目实践二(用户登录实现)

学习目的&#xff1a; 1、理解前后端交互过程 2、学习接口传参&#xff0c;数据返回以及页面展示 1、准备工作 创建SpringBoot项目&#xff0c;引入Spring Web依赖&#xff0c;添加前端页面到项目中。 前端代码&#xff1a; login.html <!DOCTYPE html> <html lang&…

云备份服务端

文件使用工具和json序列化反序列化工具 //文件和json工具类的设计实现 #ifndef __UTIL__ #define __UTIL__ #include<iostream> #include<fstream> #include<string> #include <vector> #include<sys/stat.h> #include"bundle.h" #inc…

68、Flink DataStream Connector 之文件系统详解

文件系统 1.概述 连接器提供了 BATCH 模式和 STREAMING 模式统一的 Source 和 Sink。 Flink FileSystem abstraction支持连接器对文件系统进行&#xff08;分区&#xff09;文件读写&#xff0c;文件系统连接器为 BATCH 和 STREAMING 模式提供了相同的保证&#xff0c;而且对…

数字孪生Digital Twin 结合建筑信息模型 BIM 在AIoT 智慧城市建设中Web 可视化大屏实践...

智慧城市建设通过将城市中的建筑、基础设施等构建 BIM 模型&#xff0c;并与实时采集的数据相结合&#xff0c;创建数字孪生体。可以实现对城市能源消耗、交通流量、环境质量等的实时监测和预测&#xff0c;优化城市规划和资源分配。 01 数字孪生 Digital Twin 数字孪生 Digita…

Spring MVC 全注解开发

1. Spring MVC 全注解开发 文章目录 1. Spring MVC 全注解开发2. web.xml 文件 的替代2.1 Servlet3.0新特性2.2 编写 WebAppInitializer 3. Spring MVC的配置3.1 Spring MVC的配置&#xff1a;开启注解驱动3.2 Spring MVC的配置&#xff1a;视图解析器3.3 Spring MVC的配置&…

【实战:python-Django发送邮件-短信-钉钉通知】

一 Python发送邮件 1.1 使用SMTP模块发送邮件 import smtplib from email.mime.text import MIMEText from email.header import Headermsg_from 306334678qq.com # 发送方邮箱 passwd luzdikipwhjjbibf # 填入发送方邮箱的授权码(填入自己的授权码&#xff0c;相当于邮箱…

SSE、Webworker 、webSocket、Http、Socket 服务器推送技术

Http协议 受浏览器的同源策略限制 HTTP 协议是一种无状态的、无连接&#xff08;短暂连接&#xff0c;客户端发送请求&#xff0c;服务器响应后即断开连接&#xff09;的、单向的应用层协议。 它采用了请求/响应模型。通信请求只能由客户端发起&#xff0c;服务端对请求做出应…

(day18) leetcode 204.计数质数

描述 给定整数 n &#xff0c;返回 所有小于非负整数 n 的质数的数量 。 示例 1&#xff1a; 输入&#xff1a;n 10 输出&#xff1a;4 解释&#xff1a;小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。示例 2&#xff1a; 输入&#xff1a;n 0 输出&#xff1a;0示例 3…

JVM--自动内存管理--JAVA内存区域

1. 运行时数据区域 灰色的线程共享&#xff0c;白色的线程独享 白色的独享就是根据个体"同生共死" 程序计数器&#xff1a; 是唯一一个没有OOM(内存溢出)的地方 是线程独享的 作用&#xff1a; 是一块较小的内存空间,是当前线程所执行的字节吗的行号指示器 由于…

智慧水利:迈向水资源管理的新时代,结合物联网、云计算等先进技术,阐述智慧水利解决方案在提升水灾害防控能力、优化水资源配置中的关键作用

本文关键词&#xff1a;智慧水利、智慧水利工程、智慧水利发展前景、智慧水利技术、智慧水利信息化系统、智慧水利解决方案、数字水利和智慧水利、数字水利工程、数字水利建设、数字水利概念、人水和协、智慧水库、智慧水库管理平台、智慧水库建设方案、智慧水库解决方案、智慧…

docker 安装 onlyoffice

1.文档地址 Installing ONLYOFFICE Docs for Docker on a local server - ONLYOFFICE 2.安装onlyoffice docker run -i -t -d -p 9000:8000 --restartalways -e JWT_ENABLEDfalse onlyoffice/documentserver 如果发现镜像无法下载,可以尝试更换镜像源 {"registry-mir…

JVM和类加载机制-01[JVM底层架构和JVM调优]

JVM底层 Java虚拟机内存模型JVM组成部分五大内存区域各自的作用虚拟机栈(线程栈)栈帧内存区域 本地方法栈程序计数器为什么jvm要设计程序计数器&#xff1f; 堆方法区 JVM优化-堆详解JVM底层垃圾回收机制jvm调优工具jvisualvm.exeArthas工具使用 Java虚拟机内存模型 JVM跨平台原…

2024年初级注册安全工程师职业资格考试首次开考!

​2024年初级注册安全工程师考试首次开考&#xff08;注&#xff1a;该考试由各省人事考试局组织考试&#xff09;。目前未取得中级注册安全工程师证书的各位同学&#xff0c;可以关注该考试&#xff0c;毕竟初级考证相对较容易&#xff0c;先去考一个。 目前初安开考地区汇总…

PHP多功能投票微信小程序系统源码

&#x1f389;一键决策&#xff0c;尽在掌握&#xff01;多功能投票小程序&#xff0c;让选择不再纠结&#x1f914; &#x1f4f2;【开篇&#xff1a;告别传统&#xff0c;拥抱便捷投票新时代】&#x1f4f2; 还在为组织投票活动手忙脚乱&#xff1f;或是面对众多选项犹豫不…

技术成神之路:设计模式(七)状态模式

1.介绍 状态模式&#xff08;State Pattern&#xff09;是一种行为设计模式&#xff0c;它允许一个对象在其内部状态改变时改变其行为。这个模式将状态的相关行为封装在独立的状态类中&#xff0c;并将不同状态之间的转换逻辑分离开来。 2.主要作用 状态模式的主要作用是让一个…