c++设计模式三:工厂模式

        本文通过一个例子简单介绍简单工厂模式、工厂模式和抽象工厂模式。

1.简单工厂(静态)

        假如我想换个手机,换什么手机呢?可以考虑苹果或者华为手机,那我们用简单工厂模式来实现这个功能:

        我们关注的产品是手机,那生产手机的工厂有苹果,有华为,用户也不确定选哪种怎么办?这里用简单工厂模式:定义两个枚举类型,然后写一个工厂类,根据用户传入的枚举类型生产对应品牌的手机:

手机基类:

#pragma once
class MyPhone
{
public:MyPhone(double price);~MyPhone();double getPrice() { return m_price; }
private:double m_price;
};
#include "MyPhone.h"MyPhone::MyPhone(double price) :m_price(price)
{
}
MyPhone::~MyPhone()
{
}

苹果手机:

#pragma once
#include "MyPhone.h"
class Phone_Apple:public MyPhone
{
public:Phone_Apple(double price);~Phone_Apple();
};
#include "Phone_Apple.h"
#include "stdio.h"
Phone_Apple::Phone_Apple(double price):MyPhone(price)
{printf("This is iPhone!");
}
Phone_Apple::~Phone_Apple()
{
}

华为手机:

#pragma once
#include "MyPhone.h"class Phone_Huawei :public MyPhone
{
public:Phone_Huawei(double price);~Phone_Huawei();
};
#include "Phone_Huawei.h"
#include "stdio.h"
Phone_Huawei::Phone_Huawei(double price) :MyPhone(price)
{printf("This is HUAWEI!");
}
Phone_Huawei::~Phone_Huawei()
{
}

简单工厂类:

#pragma once
#include "MyPhone.h"
enum phoneType
{APPLE_Phone,HUAWEI_Phone
};
class SimpleFactory
{
public:SimpleFactory();~SimpleFactory();MyPhone* createPhone(phoneType type);
};
#include "SimpleFactory.h"
#include "Phone_Apple.h"
#include "Phone_Huawei.h"
SimpleFactory::SimpleFactory()
{}
SimpleFactory::~SimpleFactory()
{
}
MyPhone* SimpleFactory::createPhone(phoneType type)
{MyPhone* phone = nullptr;switch (type){case APPLE_Phone:phone = new Phone_Apple(6000);break;case HUAWEI_Phone:phone = new Phone_Huawei(5600);break;}return phone;
}

用户根据自定义类型修改创建:

	SimpleFactory* factory = new SimpleFactory();//用户指定要苹果MyPhone* phone = factory->createPhone(APPLE_Phone);cout << "Price: " << phone->getPrice() << endl;delete phone;delete factory;

2.工厂模式        

        这里的工厂类似于一个手机销售店,你需要什么手机就提供什么手机,没有问题,如果用户增加了需求,想要添加三星、OPPO等,怎么办?

  1. 可以分别继承Myphone类,分别实现不同产品;
  2. 在SimpleFactory类中添加对应类别;
  3. 在createPhone方法中添加对应类别(还要引入对应的新的类和头文件);
  4. 可通过配置文件等方式准备好已有的类型供用户选择调用;

        很明显每次都要对原文件修改,如何避免呢?这里进入工厂模式:将生产手机的工厂抽象出来,然后将具体的生产厂家继承自这个抽象工厂,分别创建自己的产品:

抽象工厂类:

#pragma once
#include "MyPhone.h"
class IFactory
{
public:IFactory();~IFactory();virtual MyPhone* createPhone() = 0;
};

华为工厂:

#pragma once
#include "IFactory.h"
#include "MyPhone.h"
class HuaweiFactory : public IFactory
{
public:HuaweiFactory();~HuaweiFactory();virtual MyPhone* createPhone();
};
#include "HuaweiFactory.h"
#include "Phone_Huawei.h"
HuaweiFactory::HuaweiFactory()
{
}
HuaweiFactory::~HuaweiFactory()
{
}
MyPhone* HuaweiFactory::createPhone()
{MyPhone* phone = new Phone_Huawei(5600);return phone;
}

苹果工厂:

#pragma once
#include "IFactory.h"
#include "MyPhone.h"
class IphoneFactory :	public IFactory
{
public:IphoneFactory();~IphoneFactory();virtual MyPhone* createPhone();
};
#include "IphoneFactory.h"
#include "Phone_Apple.h"
IphoneFactory::IphoneFactory()
{
}
IphoneFactory::~IphoneFactory()
{
}
MyPhone* IphoneFactory::createPhone()
{MyPhone* phone = new Phone_Apple(6000);return phone;
}
	//3.2 工厂模式IFactory* factory = new IphoneFactory();MyPhone* phone = factory->createPhone();cout << "Price: " << phone->getPrice() << endl;IFactory* factory1 = new HuaweiFactory();MyPhone* phone1 = factory1->createPhone();cout << "Price: " << phone1->getPrice() << endl;delete phone;delete phone1;delete factory;delete factory1;

 3.抽象工厂模式

        这时,如果用户需要增加产品类型,比如华为的平板、苹果的平板怎么办?这就要引入抽象工厂模式了。 

  1. 将产品类进行抽象(这里可能会涉及多种产品);
  2. 写出具体的产品类;
  3. 将工厂类进行抽象;
  4. 具体工厂生产对应的产品(一个工厂可以生产自己品牌的多种产品)

 在原来代码基础上进行修改:

产品抽象类:

#pragma once
class MyPhone
{
public:MyPhone(double price);~MyPhone();double getPrice() { return m_price; }
private:double m_price;
};class MyPad
{
public:MyPad(double price);~MyPad();double getPrice() { return m_price; }
private:double m_price;
};

苹果产品类:

#pragma once
#include "MyPhone.h"
class Phone_Apple:public MyPhone
{
public:Phone_Apple(double price);~Phone_Apple();
};
class Pad_Apple :public MyPad
{
public:Pad_Apple(double price);~Pad_Apple();
};

华为产品类:

#pragma once
#include "MyPhone.h"class Phone_Huawei :public MyPhone
{
public:Phone_Huawei(double price);~Phone_Huawei();
};
class Pad_Huawei :public MyPad
{
public:Pad_Huawei(double price);~Pad_Huawei();
};

抽象工厂类:

#pragma once
#include "MyPhone.h"
class IFactory
{
public:IFactory();~IFactory();virtual MyPhone* createPhone() = 0;virtual MyPad* createPad() = 0;
}

具体工厂类:

#pragma once
#include "IFactory.h"
#include "MyPhone.h"
#include "Phone_Apple.h"
class IphoneFactory :	public IFactory
{
public:IphoneFactory();~IphoneFactory();virtual MyPhone* createPhone(){MyPhone* phone = new Phone_Apple(6000);return phone;}virtual MyPad* createPad() {MyPad* phone = new Pad_Apple(4900);return phone;}
};
#pragma once
#include "IFactory.h"
#include "MyPhone.h"
#include "Phone_Huawei.h"
class HuaweiFactory : public IFactory
{
public:HuaweiFactory();~HuaweiFactory();virtual MyPhone* createPhone() {MyPhone* phone = new Phone_Huawei(5600);return phone;}virtual MyPad* createPad() {MyPad* phone = new Pad_Huawei(4600);return phone;}
};

调用:

	//3.3 抽象工厂模式IFactory* factory = new HuaweiFactory();MyPad* pad = factory->createPad();cout << "Price: " << pad->getPrice() << endl;MyPhone* phone = factory->createPhone();cout << "Price: " << phone->getPrice() << endl;delete pad;delete phone;delete factory;

4.总结对比

 三种方法使用选择:

        分别理解三种模式并不困难,关键就在于根据实际问题实际情况选用不同的模式,先总结如下思考方式,供参考:

  •         当产品类型固定时可选择简单工厂模式(这里可以认为是零维的,即不用考虑其他维度);
  •         当产品涉及到不同厂商时,将工厂抽象化,不同厂商实现大厂的接口(这里可以认为是一维的,除了产品自身还需考虑厂商问题);
  •         当涉及到不同厂商的不同产品时,将工厂和产品分别抽象化(这里可以认为是二维的,考虑产品的种类以及厂商问题);

 总之要尽量满足OOP七大原则:

  • 开闭原则: 一个软件的实体应当对扩展开放,对修改关闭
  • 依赖倒转原则: 要针对接口编程,不要针对实现编程
  • 迪米特法则:只与你直接的朋友通信,而避免和陌生人通信

   三种方式的对比:

简单(静态)工厂模式:

        用来生产同一等级结构中的任意产品(对于增加新的产品,需要修改已有代码;

工厂方法模式:

        用来生产同一等级结构中的固定产品(支持增加任意产品)

        优点:

  • 你可以避免创建者和具体产品之间的紧密耦合。
  • 单一职责原则。你可以将产品创建代码放在程序的单一位置,从而使得代码更容易维护。
  • 开闭原则。无需更改现有客户端代码,你就可以在程序中引入新的产品类型。

      缺点:

  • 应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂。最好的情况是将该模式引入创建者类的现有层次结构中。

抽象工厂模式:

         围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。

        优点:

  • 应用工厂方法模式需要引入许多新的子类,代码可能会因此变得更复杂。最好的情况是将该模式引入创建者类的现有层次结构中。

        缺点:

  •   由于采用该模式需要向应用中引入众多接口和类,代码可能会比之前更加复杂。

参考文献:【精选】设计模式之工厂模式(简单工厂、工厂方法、抽象工厂)_简单工厂模式 抽象工厂模式-CSDN博客1. 工厂方法模式(Factory Method) (yuque.com)2. 抽象工厂模式(Abstract Factory) (yuque.com)

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

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

相关文章

selenium判断元素可点击、可见、可选

1、判断元素是否可以点击 判断元素是否可以点击&#xff0c;WebElement对象调用is_enabled() is_enabled()方法返回一个布尔值&#xff0c;若可点击返回&#xff1a;True。若不可点击则返回&#xff1a;False from selenium import webdriver import time from selenium.web…

OpenCV C++ 图像处理实战 ——《缺陷检测》

OpenCV C++ 图像处理实战 ——《缺陷检测》 一、结果演示二、缺陷检测算法2.1、多元模板图像2.2、训练差异模型三、图像配准3.1 功能源码3.1 功能效果四、多元模板图像4.1 功能源码五、缺陷检测5.1 功能源码六、源码测试图像下载总结一、结果演示

ARP和DDOS攻击防御介绍

✍ 如何利用ARP漏洞进行攻击&#xff1f; ✍ 怎样有效地防御ARP攻击&#xff1f; ✍ 如何应对DDOS攻击&#xff1f; ---- ARP -- 地址解析协议 ---- 最简单的协议 pc和交换机通信后就会更新地址表&#xff1a; ARP&#xff1a; PC1要访问百度&#xff1a; 发送一个广播…

基于SSM的个性化美食推荐系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Websocket传递JWT令牌

在访问带有[Authorize]的方法的时候&#xff0c;需要前端通过自定义报文头的形式将JWT令牌传递给后端进行验证&#xff0c;否则是不能访问带有[Authorize]的方法。 [Authorize]是用于限制对web应用程序中某些操作或控制器的访问。当[授权]属性应用于操作或控制器时&#xff0c;…

vivo自研AI大模型即将问世,智能手机行业加速迈向AI时代

当前&#xff0c;以大模型为代表的人工智能技术已发展为新一轮科技革命和产业变革的重要驱动力量&#xff0c;被视作推动经济社会发展的关键增长极。 AI大模型潮起&#xff0c;千行百业走向百舸争流的AI创新应用期&#xff0c;前沿信息技术向手机、PC、车机等消费级终端加速渗…

Beyond Compare比较规则设置 Beyond Compare怎么对比表格

在对文件进行比较时&#xff0c;文件夹内的文件可能存在不同类型、不同后缀名、不同内容等差异&#xff0c;这些差异会影响具体的比较结果&#xff0c;因此需要我们对软件的比较规则进行一些设置。接下来就让我们一起来学习一下Beyond Compare比较规则设置&#xff0c;Beyond C…

Qt+JSON简单例子

QtJSON简单例子 QtJSONexample2参考 QtJSON #include "mainwindow.h" #include "ui_mainwindow.h" #include <QtDebug> #include <QJsonObject> #include <QJsonArray> #include <QJsonDocument> #include <QTextCodec> #i…

Linux C/C++ 实现网络流量分析(性能工具)

网络流量分析的原理基于对数据包的捕获、解析和统计分析&#xff0c;通过对网络流量的细致观察和分析&#xff0c;帮助管理员了解和优化网络的性能、提高网络安全性&#xff0c;并快速排查和解决网络故障和问题。 Linux中的网络流量常见类型 在Linux中&#xff0c;网络流量可以…

3.72 Command Buffer及URP概述

一、Command Buffer 1.概念 CommandBuffer携带一系列的渲染命令&#xff0c;依赖相机&#xff0c;用来拓展渲染管线的渲染效果。而且可以指定在相机渲染的某个点执行本身的拓展渲染。Command buffers也可以结合屏幕后期效果使用。 简单来说就是可以在渲染流程中插入一些自定…

R2R 的一些小tip

批次间控制器(Run-to-run Controller)&#xff0c;以应对高混合生产的挑战。将最优配方参数与各种工业特征相关联的模型是根据历史数据离线训练的。预测的最优配方参数在线用于调整工艺条件。 批次控制(R2R control)是一种先进的工艺控制技术&#xff0c;可在运行(如批次或晶圆…

招生报名缴费小程序开发笔记(上)

前期调研 1.数字化趋势&#xff1a; 随着社会的数字化转型&#xff0c;越来越多的教育机构倾向于采用数字工具来简化和优化他们的招生和报名过程。招生报名缴费小程序是应对这一趋势的一种解决方案&#xff0c;可以提供高效、方便、快速的在线招生渠道。2.用户需求&#xff1a…

进行商城的测试用例设计思路是什么?

进行商城的测试用例设计时&#xff0c;可以考虑以下思路&#xff1a; 1. 功能测试&#xff1a;测试商城的基本功能是否正常工作&#xff0c;包括用户注册、登录、浏览商品、搜索商品、添加商品到购物车、下单、支付等。 2. 数据验证测试&#xff1a;验证商城中的数据是否正确…

HarmonyOS 快速入门TypeScript

1.什么是TypeScript&#xff0c;它和JavaScript&#xff0c;ArkTs有什么区别 ArkTS是HarmonyOS优选的主力应用开发语言。它在TypeScript&#xff08;简称TS&#xff09;的基础上&#xff0c;匹配ArkUI框架&#xff0c;扩展了声明式UI、状态管理等相应的能力&#xff0c;让开发…

jenkins自动化操作步骤(gitblit)

1、登陆地址&#xff1a; http://xxxxxxxxx.org:xxxx/ admin/xxxx 2、创建任务 选择构建一个maven项目 3、配置 最多只保留一天一个任务 选择git仓库和账号密码 选择代码对应分支 build项&#xff1a; 1&#xff09;使用父项目的pom文件&#xff1a;k56-boot/pom.xml 2&…

《python语言程序设计》(2018版)第5章编程题 第41题第3次路过。总结一下。没有走完的路

这道题最大的需要就是能够进行两个数值的对比&#xff0c;同时还能让更多的数值依次进入到对比中。 这道题的解题版本 这个版本只是能统计出谁是最大数。但是无法统计最大数出现了多少次。 number "" count 0 data_number 0 while number ! 0:number eval(inpu…

Babylonjs学习笔记(五)——创建PBR材质

书接上回&#xff0c;这里讨论PBR材质&#xff01;&#xff01;&#xff01; // 创建天空盒/* */const createSkyBox (scene:Scene):void>{const envTex CubeTexture.CreateFromPrefilteredData(./env/environment.env,scene)scene.environmentTexture envTex;scene.cre…

基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理MATLAB程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 参考文献&#xff1a; 基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理_董雷 仿真平台&#xff1a; MATLABcplex 主要内容&#xff1a; 主要为多虚拟电厂/微网的优化调度策略&#xff0c;模型…

Stable Diffusion AI绘图

提示词&#xff1a; masterpiece, best quality, 1girl, (anime), (manga), (2D), half body, perfect eyes, both eyes are the same, Global illumination, soft light, dream light, digital painting, extremely detailed CGI anime, hd, 2k, 4k background 反向提示词&…

在Go项目中二次封装Kafka客户端功能

1.摘要 在上一章节中,我利用Docker快速搭建了一个Kafka服务,并测试成功Kafka生产者和消费者功能,本章内容尝试在Go项目中对Kafka服务进行封装调用, 实现从Kafka自动接收消息并消费。 在本文中使用了Kafka的一个高性能开源库Sarama, Sarama是一个遵循MIT许可协议的Apache Kafk…