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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于群居蜘蛛算法的无人机航迹规划

基于群居蜘蛛算法的无人机航迹规划 文章目录 基于群居蜘蛛算法的无人机航迹规划1.群居蜘蛛搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用群居蜘蛛算法来优化无人机航迹规划。 …

【数据结构初阶】顺序表和链表(1)

顺序表和链表&#xff08;1&#xff09; 1.线性表2.顺序表2.1概念以及结构2.1.1静态顺序表2.1.2动态顺序表3.顺序表的实现3.1初始化内容3.2初始化函数3.3销毁函数3.4打印函数3.5扩容函数3.6尾插3.6尾删函数3.7头插函数3.8头删函数3.9查找函数3.10插入函数3.11删除函数3.12修改函…

拿到 phpMyAdmin 如何获取权限

文章目录 拿到 phpMyAdmin 如何获取权限1. outfile 写一句话木马2. general_log_file 写一句话木马 拿到 phpMyAdmin 如何获取权限 1. outfile 写一句话木马 尝试使用SQL注入写文件的方式&#xff0c;执行 outfile 语句写入一句话木马。 select "<?php eval($_REQU…

【软件安装】Windows系统中使用miniserve搭建一个文件服务器

这篇文章&#xff0c;主要介绍如何在Windows系统中使用miniserve搭建一个文件服务器。 目录 一、搭建文件服务器 1.1、下载miniserve 1.2、启动miniserve服务 1.3、指定根目录 1.4、开启访问日志 1.5、指定启动端口 1.6、设置用户认证 1.7、设置界面主题 &#xff08;…

挖掘业务场景的存储更优解

文章目录 第1章 如何用更优的数据存储方案&#xff0c;打造更稳定的架构&#xff1f;1.1 选用适合自己的数据存储方案1.1.1 关系型数据库1.1.2 非关系型数据库1.1.3 内存数据库 1.2 打造更稳定的架构1.2.1 分布式架构1.2.2 容灾备份1.2.3 监控报警1.2.4 自动化运维 1.3 案例分析…

Redis 原理缓存过期、一致性hash、雪崩、穿透、并发、布隆、缓存更新策略、缓存数据库一致性

redis过期策略 redis的过期策略可以通过配置文件进行配置 一、定期删除 redis会把设置了过期时间的key放在单独的字典中&#xff0c;定时遍历来删除到期的key。 1&#xff09;.每100ms从过期字典中 随机挑选20个&#xff0c;把其中过期的key删除&#xff1b; 2&#xff09;.…

python爬虫request和BeautifulSoup使用

request使用 1.安装request pip install request2.引入库 import requests3.编写代码 发送请求 我们通过以下代码可以打开豆瓣top250的网站 response requests.get(f"https://movie.douban.com/top250"&#xff09;但因为该网站加入了反爬机制&#xff0c;所以…

C语言 sizeof 函数内部进行计算

直接看代码 #include <stdio.h> int main() {int i 2;int j;j sizeof(i i);printf("i %d, j %d", i ,j);return 0; }执行结果&#xff1a; 可以看到 i的值一直是没有变的&#xff0c; j 是int类型下 sizeof占用的大小为 4个字节&#xff0c;不是i的 22…

牛客题霸 -- HJ43 迷宫问题

解题步骤; 参考代码&#xff1a; //最短路径下标 vector<vector<int>> MinPath; //临时路径 vector<vector<int>> tmp; int row 0; int col 0; void FindMinPath(vector<vector<int>>& nums, int i, int j) {nums[i][j]1;tmp.push…

C# OpenCvSharp Yolov8 Face Landmarks 人脸特征检测

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Dnn; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_Yolov8_Demo {public partial class frmMain…

面试题之JavaScript经典for循环(var let)

如果你也在面试找工作&#xff0c;那么也一定遇到过这道for循环打印结果的题&#xff0c;下面我们来探讨下 var循环 for(var i 0; i < 10; i) {setTimeout(function(){console.log(i)}); } 先把答案写出来 下面来讲一下原因&#xff1a; 划重点 ① var ②setTimeout() …

段页式管理方式

一、分段、分页的优缺点 1.分页管理&#xff1a;内存空间利用率高&#xff0c;无外部碎片&#xff0c;只有少量页内碎片&#xff0c;以物理结构划分&#xff0c;不便于按逻辑方式实现信息共享和保护 2.分段管理&#xff1a;为段长过大分配连续空间会很不方便&#xff0c;会产生…

基于springboot实现校园疫情防控系统项目【项目源码+论文说明】

基于springboot实现校园疫情防控系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&am…

MATLAB 安装教程(最新最全图文详解)

目录 一.简介 二.安装步骤 软件&#xff1a;MATLAB版本&#xff1a;2022b语言&#xff1a;简体中文大小&#xff1a;19.37G安装环境&#xff1a;Win11/Win10硬件要求&#xff1a;CPU2.6GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a; https://pa…

公众号留言功能有必要开吗?如何开通留言?

为什么公众号没有留言功能&#xff1f;2018年2月12日&#xff0c;TX新规出台&#xff1a;根据相关规定和平台规则要求&#xff0c;我们暂时调整留言功能开放规则&#xff0c;后续新注册帐号无留言功能。这就意味着2018年2月12日号之后注册的公众号不论个人主体还是组织主体&…

海外问卷调查是怎么做的?全方位介绍!

橙河这样说&#xff0c;相信大家应该不难理解。 国外问卷调查目前主要有三种形式&#xff1a;口子查、站点查和渠道查。橙河自己做的是渠道查。 站点查是最早的问卷形式&#xff0c;意思是我们需要登录到问卷网站上&#xff0c;就可以做问卷了。但想要在网站上做问卷&#xf…

【微信小程序开发】学习小程序的网络请求和数据处理

前言 网络请求是微信小程序中获取数据和与服务器交互的重要方式。微信小程序提供了自己的API来处理网络请求&#xff0c;使得开发者可以轻松地在微信小程序中实现数据的获取和提交。本文将介绍微信小程序中的网络请求&#xff0c;包括使用wx.request发起GET和POST请求&#xf…

【Java】HashMap集合

Map集合概述和使用 Map集合概述 Interface Map<k,v> k&#xff1a;键值类型 v&#xff1a;值的类型 Map集合的特点 键值对 映射关系 Key 和 Value一个键&#xff08;Key&#xff09;对应一个值&#xff08;Value&#xff09;键不允许重复&#xff0c;值可以重复如…

打算翻译完H264文档分享(1)

前言&#xff1a; 大家周末好&#xff0c;今天来总结一下最近的学习状态&#xff1b;大家平时看公众号的文章发现推送的文章都是关于音视频的内容&#xff0c;最近有分享过很多关于h264编解码器的内容&#xff0c;我认为这块的内容非常重要&#xff0c;可能很多人听过编解码标准…

RabbitMQ学习04

文章目录 发布确认1. 发布确认的原理2. 发布确认的策略2.1.开启发布确认的方法2.2.单个确认2.3.批量确认发布2.4.异步确认发布2.5.如何处理异步未确认消息2.6 总结&#xff1a; 发布确认 1. 发布确认的原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm …