1.前言

设计模式一共有23种,主要分为三大类型:创建型,结构型,行为型。本篇文章着重讲解的是创建型一些相关的设计模式

2.单例模式

Singleton 模式是设计模式中最为简单、最为常见、最容易实现,也是最应该熟悉和掌握的模式。Singleton 模式就是一个类只创建一个唯一的对象,即一次创建多次使用。

此前在cpp专栏里面也专门叙述了单例模式,这里就不过多的重复叙述。想了解的可以阅读这篇文章:

[c++进阶(三)]单例模式及特殊类的设计-CSDN博客

3.工厂模式

在面向对象系统设计中经常可以遇到以下的两类问题:

我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。所以就不得不在要用到子类的地方写new 对象。这样实体类的使用者必须知道实际的子类名称,以及会使程序的扩展性和维护变得越来越困难。
还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。只能在父类中写方法调用,具体调用哪一个类的方法交给子类实现。

为了解决上述问题,于是就引出了简单工厂模式,工厂方法模式和抽象工厂模式三种。

3.1 简单工厂模式

定义:简单工厂模式,又叫做静态工厂方法(Static Factory Method)模式,是由一个工厂对象决定创建出哪一种产品类的实例。

那么这里由一个工厂就指的是用一个静态对象,客户端通过调用这个静态对象,并传递参数给这个静态对象来实现不同对象的不同功能。

eg:我们通过一个基类来构建不同模型的图形,然后客户端不直接调用子类对象,而是通过一个静态工厂的方法来调用子类的相关成员函数

// 产品基类:定义统一接口
class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};// 具体产品:圆形
class Circle : public Shape {
public:void draw() override {std::cout << "画圆形" << std::endl;}
};// 具体产品:矩形
class Rectangle : public Shape {
public:void draw() override {std::cout << "画矩形" << std::endl;}
};// 无工厂的情况:客户端依赖具体产品
Shape* shape1 = new Circle();   // 客户端必须知道Circle
Shape* shape2 = new Rectangle(); // 客户端必须知道Rectangle//有工厂的情况下:
// 工厂类:负责所有产品的创建
class ShapeFactory {
public:// 根据参数决定创建哪种产品static Shape* createShape(const std::string& type) {if (type == "circle") {return new Circle();} else if (type == "rectangle") {return new Rectangle();}return nullptr; // 无效类型}
};// 客户端通过工厂获取产品,不依赖具体实现
Shape* shape1 = ShapeFactory::createShape("circle");   // 无需知道Circle
Shape* shape2 = ShapeFactory::createShape("rectangle"); // 无需知道Rectangle
shape1->draw(); // 画圆形
shape2->draw(); // 画矩形

简单工厂的优缺点:优点:不直接在客户端new一个子类,而是通过工厂类来完成一系列操作,降低了耦合性

缺点:违反了开闭原则,(对扩展开放,对修改关闭),不容易形成高内聚松耦合结构。 每当我们增加一种产品的时候就要去修改工厂方法,这样会破坏其内聚性,给维护带来额外开支。为了克服简单工厂方法模式的缺点,工厂方法模式和抽象工厂模式就被提了出来

3.2 工厂方法模式

定义:一个用于创建对象的接口,让子类决定实例化哪个类

工厂方法模式的核心思想:讨论的仍然是如何构建同一类型产品(都实现同一个接口)的问题,只不过是通过为每一种要生产的产品配备一个工厂,就是说每个工厂只生产一种特定的产品。这样做的好处就是当以后需要增加新的产品时,直接新增加一个对应的工厂就可以了,而不是去修改原有的工厂,符合编程原则的开闭原则

工厂方法模式为每一种产品生成一个对应的工厂,从而替换掉简单工厂方法模式中那个静态工厂方法。

#include <iostream>
#include <memory>// 产品基类:电脑
class Computer {
public:virtual void showInfo() const = 0;virtual ~Computer() = default;
};// 具体产品:小米电脑
class XiaomiComputer : public Computer {
public:void showInfo() const override {std::cout << "这是一台小米电脑,性价比高!" << std::endl;}
};// 具体产品:Mac电脑
class MacComputer : public Computer {
public:void showInfo() const override {std::cout << "这是一台Mac电脑,设计精美!" << std::endl;}
};// 工厂基类:定义创建电脑工厂的抽象方法
class ComputerFactory {
public:virtual std::unique_ptr<Computer> createComputer() const = 0;virtual ~ComputerFactory() = default;
};// 具体工厂:小米电脑工厂
class XiaomiComputerFactory : public ComputerFactory {
public:std::unique_ptr<Computer> createComputer() const override {return std::make_unique<XiaomiComputer>();}
};// 具体工厂:Mac电脑工厂
class MacComputerFactory : public ComputerFactory {
public:std::unique_ptr<Computer> createComputer() const override {return std::make_unique<MacComputer>();}
};// 客户端代码
int main() {// 创建小米电脑工厂std::unique_ptr<ComputerFactory> xiaomiFactory = std::make_unique<XiaomiComputerFactory>();// 通过小米工厂创建电脑std::unique_ptr<Computer> xiaomiComputer = xiaomiFactory->createComputer();xiaomiComputer->showInfo(); // 输出:这是一台小米电脑,性价比高!// 创建Mac电脑工厂std::unique_ptr<ComputerFactory> macFactory = std::make_unique<MacComputerFactory>();// 通过Mac工厂创建电脑std::unique_ptr<Computer> macComputer = macFactory->createComputer();macComputer->showInfo(); // 输出:这是一台Mac电脑,设计精美!return 0;
}

优点:不再违反开闭原则

缺点:如果要拓展,那么类会越写越多。 

3.3 抽象工厂模式

定义:抽象工厂为创建一组相关或者是相互依赖的对象提供一个接口,而不需要指定他们的具体类。

概念永远都是最难理解的,那么我们用一个实际的例子来理解这句话。

还是小米电脑和Mac电脑,那么此时我又要生产小米手机和mac手机,那么按照工厂方法模式则需要再拓展三个类,一个手机抽象类,2个具体手机类。

那么这就是两个家族之间的事了,小米家族负责生成小米手机和小米电脑,而mac家族负责生产mac电脑和mac手机。

那么这个时候抽象工厂就可以派上用场了。

还是上述例子:转换成图形如下所示:

用工厂方法模式,新增代码如下: 

// 新增:产品基类:手机
class Phone {
public:virtual void showInfo() const = 0;virtual ~Phone() = default;
};// 新增:具体产品:小米手机
class XiaomiPhone : public Phone {
public:void showInfo() const override {std::cout << "这是一台小米手机,性能强劲!" << std::endl;}
};// 新增:具体产品:Mac手机(iPhone)
class MacPhone : public Phone {
public:void showInfo() const override {std::cout << "这是一台Mac手机,生态流畅!" << std::endl;}
};

使用抽象工厂模式代码如下:

#include <iostream>
#include <memory>// ===== 产品接口 =====
// 电脑接口
class Computer {
public:virtual void showInfo() const = 0;virtual ~Computer() = default;
};// 手机接口
class Phone {
public:virtual void showInfo() const = 0;virtual ~Phone() = default;
};// ===== 具体产品 =====
// 小米电脑
class XiaomiComputer : public Computer {
public:void showInfo() const override {std::cout << "小米电脑:高性能处理器,轻薄设计" << std::endl;}
};// Mac电脑
class MacComputer : public Computer {
public:void showInfo() const override {std::cout << "Mac电脑:精致外观,流畅系统" << std::endl;}
};// 小米手机
class XiaomiPhone : public Phone {
public:void showInfo() const override {std::cout << "小米手机:高性价比,5G支持" << std::endl;}
};// Mac手机(iPhone)
class MacPhone : public Phone {
public:void showInfo() const override {std::cout << "Mac手机:iOS生态,A系列芯片" << std::endl;}
};// ===== 抽象工厂接口 =====
class DeviceFactory {
public:virtual std::unique_ptr<Computer> createComputer() const = 0;virtual std::unique_ptr<Phone> createPhone() const = 0;virtual ~DeviceFactory() = default;
};// ===== 具体工厂 =====
// 小米工厂:生产小米品牌的设备
class XiaomiFactory : public DeviceFactory {
public:std::unique_ptr<Computer> createComputer() const override {return std::make_unique<XiaomiComputer>();}std::unique_ptr<Phone> createPhone() const override {return std::make_unique<XiaomiPhone>();}
};// Mac工厂:生产Mac品牌的设备
class MacFactory : public DeviceFactory {
public:std::unique_ptr<Computer> createComputer() const override {return std::make_unique<MacComputer>();}std::unique_ptr<Phone> createPhone() const override {return std::make_unique<MacPhone>();}
};// ===== 客户端代码 =====
int main() {// 创建小米工厂,生产小米设备std::unique_ptr<DeviceFactory> xiaomiFactory = std::make_unique<XiaomiFactory>();auto xiaomiPC = xiaomiFactory->createComputer();auto xiaomiMobile = xiaomiFactory->createPhone();xiaomiPC->showInfo();    // 输出:小米电脑:高性能处理器,轻薄设计xiaomiMobile->showInfo(); // 输出:小米手机:高性价比,5G支持// 创建Mac工厂,生产Mac设备std::unique_ptr<DeviceFactory> macFactory = std::make_unique<MacFactory>();auto macPC = macFactory->createComputer();auto macMobile = macFactory->createPhone();macPC->showInfo();    // 输出:Mac电脑:精致外观,流畅系统macMobile->showInfo(); // 输出:Mac手机:iOS生态,A系列芯片return 0;
}

4.原型模式

原型模式属于创建型模式,所以它是描述如何创建对象的模式。顾名思义,先搞一个原型对象出来,然后在这个原型对象的基础上修修补补再弄出一个新对象来。

定义:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。

#include <iostream>
#include <memory>// 原型接口
class Shape {
public:virtual ~Shape() = default;virtual std::unique_ptr<Shape> clone() const = 0; // 纯虚函数,定义克隆接口virtual void printInfo() const = 0; // 纯虚函数,用于打印信息
};// 具体原型类:Circle
class Circle : public Shape {
private:int x;int y;double radius;public:// 构造函数Circle(int x, int y, double radius) : x(x), y(y), radius(radius) {}// 拷贝构造函数Circle(const Circle& other) : x(other.x), y(other.y), radius(other.radius) {std::cout << "Circle拷贝构造函数被调用" << std::endl;}// 克隆方法实现std::unique_ptr<Shape> clone() const override {std::cout << "Circle克隆方法被调用" << std::endl;return std::make_unique<Circle>(*this); // 调用拷贝构造函数}// 打印信息void printInfo() const override {std::cout << "Circle: x=" << x << ", y=" << y << ", radius=" << radius << std::endl;}
};// 具体原型类:Rectangle
class Rectangle : public Shape {
private:int x;int y;double width;double height;public:// 构造函数Rectangle(int x, int y, double width, double height) : x(x), y(y), width(width), height(height) {}// 拷贝构造函数Rectangle(const Rectangle& other) : x(other.x), y(other.y), width(other.width), height(other.height) {std::cout << "Rectangle拷贝构造函数被调用" << std::endl;}// 克隆方法实现std::unique_ptr<Shape> clone() const override {std::cout << "Rectangle克隆方法被调用" << std::endl;return std::make_unique<Rectangle>(*this); // 调用拷贝构造函数}// 打印信息void printInfo() const override {std::cout << "Rectangle: x=" << x << ", y=" << y << ", width=" << width << ", height=" << height << std::endl;}
};int main() {// 使用原型模式创建对象std::unique_ptr<Shape> circle1 = std::make_unique<Circle>(10, 20, 5.0);std::unique_ptr<Shape> circle2 = circle1->clone(); // 通过克隆方法复制对象std::unique_ptr<Shape> rect1 = std::make_unique<Rectangle>(0, 0, 100.0, 200.0);std::unique_ptr<Shape> rect2 = rect1->clone(); // 通过克隆方法复制对象// 使用拷贝构造函数直接创建对象Circle circle3(*circle1); // 直接调用Circle的拷贝构造函数Rectangle rect3(*rect1);  // 直接调用Rectangle的拷贝构造函数// 打印所有对象信息std::cout << "\n所有对象的信息:" << std::endl;circle1->printInfo();circle2->printInfo();circle3.printInfo();rect1->printInfo();rect2->printInfo();rect3.printInfo();return 0;
}

5.建造者模式

定义:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

简单来说就是将一个复杂的对象通过分成好几步来进行构建,然后统一把这好几步交给一个指挥者来来完成最后的组装。

比如组装一台电脑,那么就需要有cpu、主板、键盘、显示器等组成。

建造者模式
#include <memory>//eg:通过苹果电脑的构造理解建造者模式
class computer {//电脑要包含os,board,display
public:virtual void setboard(const string& board) = 0;virtual void setdisplay(const string& display) = 0;virtual void setos() = 0;void print() {string param = "computer paramaters:\n";param += "\tboard: " + _board + "\n";param += "\tdisplay: " + _display + "\n";param += "\tos: " + _os + "\n";cout << param << endl;}
protected:string _os;string _board;string _display;
};//具体mac电脑
class maccomputer :public computer {
public:void setboard(const string& board)  override{_board = board;}void setdisplay(const string& display) override {_display = display;}void setos() override {_os = "mac x64";}
};//抽象构建类
class builder {
public:virtual void buildboard(const string& board) = 0;virtual void builddisplay(const string& display) = 0;virtual void buildos() = 0;virtual std::shared_ptr<computer> build() = 0;
};//具体产品的构建
class macbookbuild :public builder{
public:macbookbuild() :_computer(new maccomputer()) {}void buildboard(const string& board) override {_computer->setboard(board);}void builddisplay(const string& display) override {_computer->setdisplay(display);}void buildos() override {_computer->setos();}std::shared_ptr<computer> build() {return _computer;}
private:std::shared_ptr<computer> _computer;
};class director {//指挥者负责组装一整套电脑
public:director(builder* builder):_build(builder){}void construct(const string& board, const string& display) {_build->buildboard(board);_build->builddisplay(display);_build->buildos();}
private:std::shared_ptr<builder> _build;
};int main() {builder* builder = new macbookbuild();unique_ptr<director> director(new director(builder));director->construct("罗技","三星");shared_ptr<computer> computer = builder->build();computer->print();return 0;
}

建造者模式的使用场景:当一个类的构造函数的参数超过四个,且这四个参数还是可选可不选的,那么就可以考虑使用建造者模式了。 

6.总结

我们一定要牢记设计模式是前人总结的一套可以有效解决问题的经验,不要一写代码就在考虑该使用什么设计模式,这是极其不可取的。正确的做法应该是在实现业务需求的同时,尽量遵守面向对象设计的六大设计原则即可。后期随着业务的扩展,你的代码会不断的演化和重构,在此过程中设计模式绝逼会大放异彩的。

说实话博主写完这篇文章感觉原型模式模式是不是有点多余啊,想复制原来创建的新的对象,使用拷贝构造函数不就可以了嘛,为什么还要弄一个新的设计模式出来呢。目前博主的理解就到这啦,有兴趣的可以后台TT博主一起交流呀!

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

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

相关文章

kubernetes学习笔记(一)

kubernetes学习笔记(一) kubernetes简介 ​ Kubernetes是Google开源的一个容器编排引擎&#xff0c;它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时&#xff0c;通常要部署该应用的多个实例以便对应用请求进行负载均衡。 ​ 在Kubernetes…

Eureka实战

1.创建父工程SpringCloudTestSpringCloudTest为父工程&#xff0c;用于引入通用依赖&#xff0c;如spring-boot-starter-web、lombok&#xff0c;这样子工程就可以直接继承&#xff0c;无需重复引入。在dependencyManagement标签中引入和springboot版本对应的springcloud&#…

如何把镜头对焦在超焦距上

要把镜头对焦在超焦距上&#xff0c;可以按照以下步骤操作&#xff1a;1. 计算超焦距 首先需要知道你的镜头参数和相机参数&#xff1a; 焦距 f&#xff08;如 24mm、35mm&#xff09;光圈 N&#xff08;如 f/8、f/11&#xff09;容许弥散圆直径 c&#xff08;与传感器尺寸有关…

idea docker插件连接docker失败

报错org.apache.hc.client5.http.HttpHostConnectException:Connect to http://localhost:2375 [localhost/127.0.0.1, localhost/0:0:0:o:0:0:0:1] failed:Connection refused:getsockopt解决方法&#xff1a;

【后端】.NET Core API框架搭建(6) --配置使用MongoDB

目录 1.添加包 2. 连接配置 2.1.链接字符串 2.2.连接类 3.仓储配置 3.1.仓储实现 3.2.仓储接口 4.获取配置和注册 4.1.添加配置获取方法 4.2.注册 5.常规使用案例 5.1实体 5.2.实现 5.3.接口 5.4.控制器 NET Core 应用程序中使用 MongoDB 有许多好处&#xff0c;尤其是在…

Spring AI快速入门

文章目录1 介绍1_大模型对比2_开发框架对比2 快速入门1_引入依赖2 配置模型3 配置客户端4 测试3 会话日志1_Advisor2 添加日志Advisor4 会话记忆1_定义会话存储方式2 配置会话记忆Advisor5 会话历史1_管理会话历史2 保存会话id3 查询会话历史6 后续1 介绍 SpringAI整合了全球&…

Windows下编译pthreads

本文记录在Windows下编译pthreads的流程。 零、环境 操作系统Windows 11VS Code1.92.1Git2.34.1MSYS2msys2-x86_64-20240507Visual StudioVisual Studio Community 2022CMake3.22.1 一、编译安装 1.1 下载 git clone https://git.code.sf.net/p/pthreads4w/code 1.2 构建…

WP Force SSL Pro – HTTPS SSL Redirect Boost Your Website‘s Trust in Minutes!

In the vast digital landscape where security and user trust are paramount, ensuring your WordPress site uses HTTPS is not just a recommendation—it’s a necessity. That’s where WP Force SSL Pro – HTTPS SSL Redirect steps in as your silent guardian, makin…

jvm--java代码对照字节码图解

java代码&#xff1a;无静态方法&#xff1b;&#xff08;对应字节码没有方法&#xff09; 任何一个类&#xff0c;至少有一个构造器&#xff0c;默认是无参构造java代码包含&#xff1a;静态方法java代码包含&#xff1a;静态方法、显示构造方法public class ClassInitTest {p…

动态规划题解_打家劫舍【LeetCode】

198. 打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个…

电脑安装 Win10 提示无法在当前分区上安装Windows的解决办法

原因&#xff1a; win10系统均添加快速启动功能&#xff0c;预装的win10电脑默认都是UEFI引导和GPT硬盘&#xff0c;传统的引导方式为Legacy引导和MBR硬盘&#xff0c;UEFI必须跟GPT对应&#xff0c;同理Legacy必须跟MBR对应。如果BIOS开启UEFI&#xff0c;而硬盘分区表格式为M…

大端序与小端序

理解大端序&#xff08;Big-Endian&#xff09;和小端序&#xff08;Little-Endian&#xff09;的关键在于数据在内存中存储时字节的排列顺序&#xff0c;特别是在存储多字节数据类型&#xff08;如整数、浮点数&#xff09;时。以下是清晰易懂的解释&#xff1a;核心概念 假设…

PyTorch笔记5----------Autograd、nn库

1.Autograd grad和grad_fn grad&#xff1a;该tensor的梯度值&#xff0c;每次在计算backward时都需要将前一时刻的梯度归零&#xff0c;否则梯度值会一直累加grad_fn&#xff1a;叶子结点通常为None&#xff0c;只有结果节点的grad_fn才有效&#xff0c;用于只是梯度函数时哪…

Perl 格式化输出

Perl 格式化输出 引言 Perl 是一种通用、解释型、动态编程语言&#xff0c;广泛应用于文本处理、系统管理、网络编程等领域。在Perl编程中&#xff0c;格式化输出是一种常见的需求&#xff0c;它可以帮助开发者更好地展示和打印信息。本文将详细讲解Perl中格式化输出的方法&…

Python爬虫实战:研究markdown2库相关技术

一、引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上的信息量呈指数级增长。如何高效地获取和整理这些信息成为了一个重要的研究课题。网络爬虫作为一种自动获取网页内容的技术,能够按照一定的规则,自动地抓取万维网信息,为信息的收集提供了有力手段。 Markdown …

【Linux】基本指令详解(二) 输入\输出重定向、一切皆文件、认识管道、man、cp、mv、echo、cat

文章目录一、man指令二、输入/输出重定向(echo、一切皆文件&#xff09;三、cp指令四、mv指令五、cat指令六、more/less指令七、head/tail指令八、管道初见一、man指令 Linux的指令有很多参数&#xff0c;我们不可能全记住&#xff0c;可以通过查看联机手册获取帮助。 man 指令…

MVC HTML 帮助器

MVC HTML 帮助器 引言 MVC&#xff08;模型-视图-控制器&#xff09;是一种流行的软件架构模式&#xff0c;它将应用程序的逻辑分解为三个主要组件&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Controller&#xff09…

linux下手工安装ollama0.9.6

1、去下载ollama的linux版的压缩包&#xff1a; 地址&#xff1a;https://github.com/ollama/ollama/releases2、上传到linux中。3、解压&#xff1a; tar zxvf ollama-linux-amd64-0.9.6.tgz -C /usr/local/4、如果仅仅是要手工执行&#xff0c;已经可以了&#xff1a; ollama…

kotlin布局交互

将 wrapContentSize() 方法链接到 Modifier 对象&#xff0c;然后传递 Alignment.Center 作为实参以将组件居中。Alignment.Center 会指定组件同时在水平和垂直方向上居中。 DiceWithButtonAndImage(modifier Modifier.fillMaxSize().wrapContentSize(Alignment.Center) )创建…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | ToastNotification(推送通知)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— ToastNotification组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script s…