设计模式:简单工厂模式(Simple Factory)

设计模式:简单工厂模式(Simple Factory)

  • 设计模式:简单工厂模式(Simple Factory)
    • 模式动机
    • 模式定义
    • 模式结构
    • 时序图
    • 模式实现
    • 测试
    • 模式分析
    • 实例:Qt 控件类
    • 优缺点
    • 适用环境
    • 模式应用

设计模式:简单工厂模式(Simple Factory)

简单工厂模式(Simple Factory)属于创建型模式(Creational Pattern)的一种。

创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。

创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。

模式动机

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

考虑一个简单的软件应用场景,一个软件系统可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等), 这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的外观,如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。

模式定义

简单工厂模式(Simple Factory)又称为静态工厂方法(Static Factory Method)模式。

在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

模式结构

简单工厂模式(Simple Factory)包含以下角色:

  1. 工厂(Factory):工厂角色负责实现创建所有实例的内部逻辑。
  2. 抽象产品(Abstract Product):定义了产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了产品对象的共同方法。
  3. 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。具体产品是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

在这里插入图片描述

时序图

在这里插入图片描述

模式实现

简单工厂类 SimpleFactory.h:

#ifndef _SIMPLE_FACTORY_H_
#define _SIMPLE_FACTORY_H_#include <string>
#include "ConcreteProductA.h"
#include "ConcreteProductB.h"class SimpleFactory
{
public:static AbstractProduct* createProduct(const std::string& productType){if (productType == "A")return new ConcreteProductA();else if (productType == "B")return new ConcreteProductB();return nullptr;}
};#endif // !_SIMPLE_FACTORY_H_

抽象产品类 AbstractProduct.h:

#ifndef _ABSTRACT_PRODUCT_H_
#define _ABSTRACT_PRODUCT_H_#include <iostream>class AbstractProduct
{
public:virtual void use() = 0;
};#endif // !_ABSTRACT_PRODUCT_H_

具体产品A类 ConcreteProductA.h:

#ifndef _CONCRETE_PRODUCT_A_H_
#define _CONCRETE_PRODUCT_A_H_#include "AbstractProduct.h"class ConcreteProductA : public AbstractProduct
{
public:void use() override{std::cout << "Using Concrete Product A" << std::endl;}
};#endif // !_CONCRETE_PRODUCT_A_H_

具体产品B类 ConcreteProductB.h:

#ifndef _CONCRETE_PRODUCT_B_H_
#define _CONCRETE_PRODUCT_B_H_#include "AbstractProduct.h"class ConcreteProductB : public AbstractProduct
{
public:void use() override{std::cout << "Using Concrete Product B" << std::endl;}
};#endif // !_CONCRETE_PRODUCT_B_H_

测试

测试代码 main.cpp:

#include <stdlib.h>
#include "SimpleFactory.h"
#include "ConcreteProductA.h"
#include "ConcreteProductB.h"int main()
{SimpleFactory simpleFactory;AbstractProduct* productA = simpleFactory.createProduct("A");AbstractProduct* productB = simpleFactory.createProduct("B");if (productA)productA->use();if (productB)productB->use();delete productA;delete productB;system("pause");return 0;
}

运行结果:

在这里插入图片描述

模式分析

  • 将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
  • 在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可,在实际开发中,还可以在调用时将所传入的参数保存在XML等格式的配置文件中,修改参数时无须修改任何源代码。
  • 简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。
  • 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

实例:Qt 控件类

在开发一个用户界面过程中,我需要三种控件类型,分别是按钮、图像和文本。这些控件都有一些工厂的特点,比如都有位置属性(位于界面的哪个地方)、大小属性(长度和宽度)等等。因此创建一个Item(参考Qt)作为它们的父类,Button(按钮)、Image(图像)和Text(文本)都继承于它。

下面是参考代码:

#include <iostream>  
#include <memory> 
#include <string> 
#include <stdlib.h>
using namespace std;// Item 父类
class Item
{
protected:int m_width;int m_height;public:Item(int width, int height) : m_width(width), m_height(height) {}virtual ~Item() {}
};// Button 子类
class Button : public Item
{
public:Button(int width, int heght) : Item(width, heght){cout << "用户界面创建了一个按钮" << endl;}
};// Image 子类
class Image : public Item
{
public:Image(int width, int heght) : Item(width, heght){cout << "用户界面创建了一个图像" << endl;}
};// Text 子类
class Text : public Item
{
public:Text(int width, int heght) : Item(width, heght){cout << "用户界面创建了一个文本" << endl;}
};// ItemFactory 工厂类
class ItemFactory
{
public:static unique_ptr<Item> createItem(string itemType){if (itemType == "button"){// newItem = new Button(50, 50);return make_unique<Button>(50, 50);}else if (itemType == "image"){// newItem = new Image(100, 100);return make_unique<Image>(100, 100);}else if (itemType == "text"){// newItem = new Text(100, 30);return make_unique<Text>(100, 30);}return NULL;}
};int main()
{ItemFactory itemFac;auto pI1 = itemFac.createItem("button"); // 创建了一个 Buttonauto pI2 = itemFac.createItem("image"); // 创建了一个 Imageauto pI3 = itemFac.createItem("text"); // 创建了一个 Text//    delete pI1;
//    delete pI2;
//    delete pI3;system("pause");return 0;
}

我们使用简单工厂模式后,创建各种各样的控件,就不用和它们控件本身的类打交道(Button、Image、Text),而是通过ItemFactory的成员函数createFactory,将不同字符串标识传入进去,从而返回不同的控件,这其实就是一种封装变化。

优缺点

优点:

  1. 封装性好: 简单工厂模式封装了对象创建的细节,客户端不需要直接实例化具体的产品类。这有助于隐藏具体产品类的实现细节,使得客户端代码更加简洁和易于维护。
  2. 解耦: 简单工厂模式降低了客户端与具体产品类之间的耦合度。客户端只需要与工厂类交互,而不需要知道具体产品类的实现细节。这有助于减少代码的依赖性和提高系统的可维护性。
  3. 代码复用: 工厂类集中了产品对象的创建逻辑,可以在多个地方重用该工厂类来创建对象,提高了代码的复用性。
  4. 扩展性好: 当需要添加新的产品类时,只需要在工厂类中添加相应的创建逻辑,而无需修改客户端代码。这符合开闭原则,即对扩展开放,对修改封闭。

缺点:

  1. 违反单一职责原则: 简单工厂类通常负责创建多种类型的产品对象,这可能导致工厂类的职责过多,违反了单一职责原则。当产品类型较多时,工厂类的代码可能会变得庞大而难以维护。
  2. 类型判断逻辑复杂: 简单工厂模式通常需要根据客户端提供的参数或类型信息来判断需要创建哪种类型的产品对象。随着产品类型的增加,类型判断逻辑可能会变得复杂和易错。
  3. 不易于扩展新的产品族: 简单工厂模式是针对一个产品族设计的,如果需要添加新的产品族(即一组具有共同主题的产品),可能需要修改工厂类的代码,这违反了开闭原则。
  4. 不易于使用继承等面向对象特性: 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构;由于简单工厂模式通常直接返回具体产品类的实例,而不是通过继承等面向对象特性来创建对象,因此可能无法充分利用面向对象编程的优势。

适用环境

C++ 简单工厂模式的应用场景主要包括以下几种情况:

  1. 创建对象不需要知道具体类的情况: 客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
  2. 需要创建的对象较少且不会经常变动: 由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。

模式应用

  1. JDK类库中广泛使用了简单工厂模式,如工具类java.text.DateFormat,它用于格式化一个本地日期或者时间。
    public final static DateFormat getDateInstance();
    public final static DateFormat getDateInstance(int style);
    public final static DateFormat getDateInstance(int style,Locale
    locale);
    
  2. Java加密技术。
    比如,获取不同加密算法的密钥生成器:
    public final static DateFormat getDateInstance();
    public final static DateFormat getDateInstance(int style);
    public final static DateFormat getDateInstance(int style,Locale locale);
    

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

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

相关文章

关基网络战时代,赛宁网安电力网络攻防靶场全面提升电网安全防护力

随着网络空间成为与陆地、海洋、天空、太空同等重要的人类活动新领域&#xff0c;自网络空间向物理电网发起攻击&#xff0c;破坏电力等国家关键基础设施成为当前大国博弈、大规模战争的重要手段和常态进攻形式。同时&#xff0c;新型电力系统建设发展驱动电力系统形态和控制方…

基于Springboot的社区待就业人员信息管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的社区待就业人员信息管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三…

TaskWeaver使用记录

TaskWeaver使用记录 1. 基本介绍2. 总体结构与流程3. 概念细节3.1 Project3.2 Session3.3 Memory3.4 Conversation3.5 Round3.6 Post3.7 Attachment3.8 Plugin3.9 Executor 4. 代码特点5. 使用过程5.1 api调用5.2 本地模型使用5.3 添加插件 6. 存在的问题与使用体验6.1 判别模型…

笔记本电脑坏了硬盘数据会丢失吗 笔记本电脑坏了如何取出硬盘的资料 数据恢复软件

笔记本电脑对我们真的非常重要了&#xff0c;是实现无纸化办公和学习的重要工具&#xff0c;但是如果笔记本电脑坏了我们存储在电脑里的资料该怎么办&#xff1f;笔记本电脑坏了硬盘数据会丢失吗&#xff1f;相信有许多朋友都会有这样的担忧。本文今天就为大家解决笔记本电脑坏…

【银角大王———Django学习DAY0——基础准备】

银角大王——Django学习前情提要 &#xff08;1&#xff09;在pycharm中下载Flask&#xff08;2&#xff09;使用Flask&#xff08;3&#xff09;下载BootStrap框架&#xff08;4&#xff09; 使用BootStrap框架 &#xff08;1&#xff09;在pycharm中下载Flask 在设置——项目…

【若依】代码生成详细教程(单表、主从表、树形表增删改查)

若依代码生成开发接口 修改代码生成配置一、单表实现增删改查1. 新建数据库表结构2. 新建模块&#xff0c;解决项目依赖3. 启动项目&#xff0c;新建菜单4. 导入数据表&#xff0c;自动生成代码5. 将生成代码粘贴到对应的模块&#xff0c;执行生成的sql&#xff08;用于生成菜单…

GitHub/R3D3项目环境配置踩坑记录

1、前言 项目链接地址&#xff1a;SysCV/r3d3 (github.com) 按照安装步骤容易出现的问题&#xff0c;environment.yaml文件中安装相关包&#xff0c;其中还有两个pip install githttps://github.com/..........这两个建议注释掉&#xff0c;后面再来安装这两个。 2、问题及解…

【C++题解】1020. 算算和是多少

问题&#xff1a;1020. 算算和是多少 类型&#xff1a;基本运算、拆位求解 题目描述&#xff1a; 输入一个三位正整数&#xff0c;然后与它倒过来的数相加&#xff0c;输出和。 如&#xff1a;输入167 &#xff0c;则和为167761928。 输入&#xff1a; 只有一行&#xff0c…

全开源小狐狸Ai系统 小狐狸ai付费创作系统 ChatGPT智能机器人2.7.6免授权版

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 测试环境&#xff1a;Linux系统CentOS7.6、宝塔、PHP7.4、MySQL5.6&#xff0c;根目录public&#xff0c;伪静态thinkPHP&#xff0c;开启ssl证书 具有文章改写、广告营销文案、编程…

PostgreSql-Install

PostgreSql源码安装 一、源代码下载二、操作系统配置三、编译安装四、启动数据库五、相关命令 PostgreSQL是一个强大的 开源对象关系数据库系统&#xff0c;它使用并扩展了SQL语言&#xff0c;并结合了许多功能&#xff0c;可以安全地存储和扩展最复杂的数据工作负载。 一、源…

gin框架提高篇(四)

参数校验&#xff08;一&#xff09; uuid包&#xff1a;https://github.com/satori/go.uuid 因为作者更改了参数限制&#xff0c;导致会出问题 → 问题解决 package mainimport ("fmt""github.com/gin-gonic/gin""github.com/go-playground/validato…

盲人盲杖:科技革新,助力视障人士独立出行

在我们的社会中&#xff0c;盲人朋友们以其坚韧的精神风貌&#xff0c;生动诠释着生活的多样与可能。然而&#xff0c;当我们聚焦于他们的日常出行&#xff0c;那些普通人视为寻常的街道、路口&#xff0c;却成为他们必须面对的严峻挑战。如何切实提升盲人盲杖的功能&#xff0…

【Linux进阶之路】高级IO

一、 铺垫 I&#xff0c;即input为输入&#xff1b;O&#xff0c;即output为输出&#xff0c;IO&#xff0c;即input output为输入输出。IO一般是基于网卡&#xff0c;磁盘&#xff0c;光盘&#xff0c;U盘&#xff0c;磁盘&#xff0c;磁带等毫秒级别的外存&#xff0c;相较…

Python实现贪吃蛇

提供学习或者毕业设计使用,功能基本都有,不能和市场上正式游戏相提比论,请理性对待!通过购买专栏或者CSDN问答提问,采纳后,私信博主。提供源码! 说明:需要的话联系博主!谢谢。 代码: import pygame import random import tkinter as tk from tkinter import mess…

BetterZip 5 for Mac:轻松解压缩的得力助手

BetterZip 5 for Mac是一款专为苹果电脑用户设计的压缩与解压软件&#xff0c;以其强大的功能和便捷的操作赢得了广大用户的喜爱。 BetterZip 5 for Mac v5.3.4中文版下载 这款软件支持多种主流的压缩格式&#xff0c;如ZIP、RAR、7-Zip等&#xff0c;满足了用户多样化的需求。…

WordPress 主题选择与自定义配置

最近我在使用wordpress网站进行建站。 我是使用的hostease的主机产品进行wordpress建站&#xff0c;在选择wordpress主题时颇为头疼。后来咨询了hostease的客服人员&#xff0c;他们家的技术人员提供了诸多帮助。在WordPress网站建设时&#xff0c;主题选择对于建立各类网站至关…

【MIT6.824】lab2C-persistence, lab2D-log compaction 实现笔记

引言 lab2C的实验要求如下 Complete the functions persist() and readPersist() in raft.go by adding code to save and restore persistent state. You will need to encode (or “serialize”) the state as an array of bytes in order to pass it to the Persister. Us…

记录——FPGA的学习路线

文章目录 一、前言二、编程语言2.1 书籍2.2 刷题网站2.3 仿真工具 三、基础知识3.1 专业基础课3.2 fpga相关专业知识 四、开发工具五、动手实验 一、前言 也不是心血来潮想学习fpga了&#xff0c;而是祥哥还有我一个国科大的同学都在往fpga这个方向走 并且看过我之前文章的同…

合并有序表 (顺序存储 和 链式存储 方式实现)

代码详细解析: 合并有序表文章浏览阅读1.4k次&#xff0c;点赞6次&#xff0c;收藏7次。●假设有两个有序表 LA和LB , 将他们合并成一个有序表LC●要求不破坏原有的表 LA和 LB构思:把这两个表, 合成一个有序表 , 不是简简单单吗?就算是把他们先遍历不按顺序插入到表 C里面 , …

万物皆可计算|下一个风口:近内存计算-2

虽然PIM可以有缓解内存墙的问题&#xff0c;但是PIM设计面临着一系列技术和工程上的挑战&#xff0c;这些挑战直接影响着PIM技术的实用化和广泛应用&#xff1a; 地址翻译与操作映射&#xff1a; 在传统计算机体系结构中&#xff0c;地址空间由操作系统管理和调度&#xff0c;通…