常用设计模式(工厂方法,抽象工厂,责任链,装饰器模式)

news2024/12/25 2:15:47

前言

有关设计模式的其他常用模式请参考
单例模式的实现
常见的设计模式(模板与方法,观察者模式,策略模式)

工程方法

定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 ——《设计模式》GoF

要点

解决创建过程比较复杂,希望对外隐藏这些细节的场景;

  • 比如连接池、线程池
  • 隐藏对象真实类型;
  • 对象创建会有很多参数来决定如何创建;
  • 创建对象有复杂的依赖关系;

本质

延迟到子类来选择实现;

结构图

在这里插入图片描述

举例

实现一个导出数据的接口,让客户选择数据的导出方式;

代码

class IExport
{
protected:
	IExport() {}
	virtual ~IExport() {}
public:
	virtual void exportFile() = 0;
};

class JSONExport :public IExport
{
public:
	JSONExport() {}
	~JSONExport() {}
	void exportFile()
	{
		std::cout << "export json file" << std::endl;
	}
};
class TxtFileExport :public IExport
{
public:
	TxtFileExport() {}
	~TxtFileExport() {}
	void  exportFile()
	{
		std::cout << "export txt  file" << std::endl;
	}
};
class XMLExport :public IExport
{
public:
	XMLExport() {}
	~XMLExport() {}
	void  exportFile()
	{
		std::cout << "export xml file" << std::endl;
	}
};

class IFactoryMethodExport
{
public:
	virtual IExport* createExport() = 0;//创建比较复杂,使用一个函数来创建
};

class FactoryMethodJSONExport :public IFactoryMethodExport
{
public:
	IExport* createExport() {
		//比较多的参数初始化
		jsonExport = new JSONExport();//这里没有使用参数这些
	  //其他初始化操作
	}
private:
	JSONExport* jsonExport;
};

class FactoryMethodXMLExport :public IFactoryMethodExport
{
public:
	IExport* createExport() {
		//比较多的参数初始化
		xmlExport = new XMLExport();//这里没有使用参数这些
	  //其他初始化操作
	}
private:
	XMLExport* xmlExport;
};

class FactoryMethodTxtFileExport :public IFactoryMethodExport
{
public:
	IExport* createExport() {
		//比较多的参数初始化
		txtFileExport = new TxtFileExport();//这里没有使用参数这些
	  //其他初始化操作
		return txtFileExport;
	}
private:
	TxtFileExport* txtFileExport;
};

抽象工厂

定义

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。——《设计模式》GoF
其实和工厂方法是类似的,只是在工厂中创建多个对象。

结构图

在这里插入图片描述

例子

实现一个拥有导出导入数据的接口,让客户选择数据的导出导入方式;

代码

class IExport {
public:
    virtual bool Export(const std::string &data) = 0;
    virtual ~IExport(){}
};

class ExportXml : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

class ExportJson : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

class ExportTxt : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

class ExportCSV : public IExport {
public:
    virtual bool Export(const std::string &data) {
        return true;
    }
};

class IImport {
public:
    virtual bool Import(const std::string &data) = 0;
    virtual ~IImport(){}
};

class ImportXml : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};

class ImportJson : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};

class ImportTxt : public IImport {
public:
    virtual bool Import(const std::string &data) {
        return true;
    }
};

// 对于初学者: 知道扩展代码
// 5年
class ImportCSV : public IImport {
public:
    virtual bool Import(const std::string &data) {
        // ....
        return true;
    }
};

class IDataApiFactory {
public:
    IDataApiFactory() {
        _export = nullptr;
        _import = nullptr;
    }
    virtual ~IDataApiFactory() {
        if (_export) {
            delete _export;
            _export = nullptr;
        }
        if (_import) {
            delete _import;
            _import = nullptr;
        }
    }
    bool Export(const std::string &data) {
        if (_export == nullptr) {
            _export = NewExport();
        }
        return _export->Export(data);
    }
    bool Import(const std::string &data) {
        if (_import == nullptr) {
            _import = NewImport();
        }
        return _import->Import(data);
    }
protected:
    virtual IExport * NewExport(/* ... */) = 0;
    virtual IImport * NewImport(/* ... */) = 0;
private:
    IExport *_export;
    IImport *_import;
};

class XmlApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportXml;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportXml;
        // 可能之后有什么操作
        return temp;
    }
};

class JsonApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportJson;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportJson;
        // 可能之后有什么操作
        return temp;
    }
};
class TxtApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportTxt;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportTxt;
        // 可能之后有什么操作
        return temp;
    }
};

class CSVApiFactory : public IDataApiFactory {
protected:
    virtual IExport * NewExport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IExport * temp = new ExportCSV;
        // 可能之后有什么操作
        return temp;
    }
    virtual IImport * NewImport(/* ... */) {
        // 可能有其它操作,或者许多参数
        IImport * temp = new ImportCSV;
        // 可能之后有什么操作
        return temp;
    }
};

// 相关性  依赖性    工作当中
int main () {
    IDataApiFactory *factory = new CSVApiFactory();
    factory->Import("hello world");
    factory->Export("hello world");
    return 0;
}

责任链模式

定义

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。 ——《设计模式》GoF

要点

  • 解耦请求方和处理方,请求方不知道请求是如何被处理,处理方的组成是由相互独- 立的子处理构成,子处理流程通过链表的方式连接,子处理请求可以按任意顺序组合;
  • 责任链请求强调请求最终由一个子处理流程处理;通过了各个子处理条件判断;
  • 责任链扩展就是功能链,功能链强调的是,一个请求依次经由功能链中的子处理流程处理;
  • 将职责以及职责顺序运行进行抽象,那么职责变化可以任意扩展,同时职责顺序也可以任意扩展;

本质

  • 分离职责,动态组合;

结构图

在这里插入图片描述

例子

请求流程,1 天内需要主程序批准,3 天内需要项目经理批准,3 天以上需要老板批准;
在前面链接的说明了设计模式主要是设计需求的变化点,稳定点是固定的流程。
在这里:稳定点是处理流程是稳定的(首选判断是否能够处理,如果不能处理,则交给更高层处理,可以抽象出是否能够处理接口和处理接口)。变化点包括:天数,职责人个数(后续可能会增加更多的项目职责)。

代码

#include <string>
struct WorkerContext {
	std::string name;
	int day;
};

class IWorker{
public:
	IWorker(WorkerContext& context) :context(context) 
	{ 
	}
	//处理流程是固定的,稳定点不变
	bool handle() {
		if (isCanHandle()) {//可以处理
	       return handRequest();
		}
		else if(next){//不可以处理,交给下个处理者处理
			return next->handle();
		}
		std::cout << "无法处理" << std::endl;
		return false;
	}
	void setNextHandler(IWorker* _next)//设置下一个处理者
	{
		next = _next;
	}
protected:
	virtual bool isCanHandle() = 0;//是否可以处理
	virtual bool handRequest() = 0;//处理
	WorkerContext& context;
private:
	IWorker* next = nullptr;//下一个流程处理者
};

//
class MainProgram :public IWorker {
public:
	MainProgram(WorkerContext& context) :IWorker(context) {}
private:
	bool isCanHandle() {
		if (context.day <= 1)
		{
			return true;
		}
		return false;
	}
	bool handRequest() {
		std::cout << "MainProgram 同意" << context.name << "天数" << context.day << std::endl;
		return true;
	}
};
class ProjectManager :public IWorker {
public:
	ProjectManager(WorkerContext& context) :IWorker(context) {}
private:
	bool isCanHandle() {
		if (context.day <= 3)
		{
			return true;
		}
		return false;
	}
	bool handRequest() {
		std::cout << "ProjectManager 同意" << context.name << "天数" << context.day << std::endl;
		return true;
	}
};

class Boss :public IWorker {
public:
	Boss(WorkerContext& context) :IWorker(context) {}
private:
	bool isCanHandle() {
		if (context.day > 3 && context.day < 10)
		{
			return true;
		}
		return false;
	}
	bool handRequest() {
		std::cout << "Boss 同意" << context.name << "天数" << context.day << std::endl;
		return true;
	}
};

int main{
	WorkerContext context;
	context.day = 10;
	context.name = "susan";
	IWorker* worker1 = new MainProgram(context);
	IWorker* worker2 = new ProjectManager(context);
	IWorker* worker3 = new Boss(context);
	worker1->setNextHandler(worker2);
	worker2->setNextHandler(worker3);
	worker1->handle();
}

装饰器模式

定义

动态地给一个对象增加一些额外的职责。就增加功能而言,装饰器模式比生产子类更为灵活。—— 《设计模式》GoF

要点

- 通过采用组合而非继承的手法, 装饰器模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。 避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
- 不是解决“多子类衍生问题”问题,而是解决“父类在多个方向上的扩展功能”问题;
- 装饰器模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,实现复用装饰器的功能;

本质

动态组合

例子

普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能针对不同的职位产生不同的奖金组合;

代码

#include <iostream>
// 普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能产生不同的奖金组合;
// 销售奖金 = 当月销售额 * 4%
// 累计奖金 = 总的回款额 * 0.2%
// 部门奖金 = 团队销售额 * 1%
// 环比奖金 = (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
using namespace std;
class Context {
public:
    bool isMgr;
    // User user;
    // double groupsale;
};


class CalcBonus {    
public:
    CalcBonus(CalcBonus * c = nullptr) : cc(c) {}
    virtual double Calc(Context &ctx) {
        return 0.0; // 基本工资
    }
    virtual ~CalcBonus() {}

protected:
    CalcBonus* cc;
};

class CalcMonthBonus : public CalcBonus {
public:
    CalcMonthBonus(CalcBonus * c) : CalcBonus(c) {}
    virtual double Calc(Context &ctx) {
        double mbonus /*= 计算流程忽略*/; 
        return mbonus + cc->Calc(ctx);
    }
};

class CalcSumBonus : public CalcBonus {
public:
    CalcSumBonus(CalcBonus * c) : CalcBonus(c) {}
    virtual double Calc(Context &ctx) {
        double sbonus /*= 计算流程忽略*/; 
        return sbonus + cc->Calc(ctx);
    }
};

class CalcGroupBonus : public CalcBonus {
public:
    CalcGroupBonus(CalcBonus * c) : CalcBonus(c) {}
    virtual double Calc(Context &ctx) {
        double gbnonus /*= 计算流程忽略*/; 
        return gbnonus + cc->Calc(ctx);
    }
};

class CalcCycleBonus : public CalcBonus {
public:
    CalcCycleBonus(CalcBonus * c) : CalcBonus(c) {}
    virtual double Calc(Context &ctx) {
        double gbnonus /*= 计算流程忽略*/; 
        return gbnonus + cc->Calc(ctx);
    }
};

int main() {
    // 1. 普通员工
    Context ctx1;
    CalcBonus *base = new CalcBonus();
    CalcBonus *cb2 = new CalcSumBonus(base);
    CalcBonus *cb1 = new CalcMonthBonus(cb2);


    cb2->Calc(ctx1);
    // 2. 部门经理
    Context ctx2;
    CalcBonus *cb3 = new CalcGroupBonus(cb2);
    cb3->Calc(ctx2);
}

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

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

相关文章

Spring Boot 优雅实现统一数据返回格式+统一异常处理+统一日志处理

在我们的项目开发中&#xff0c;我们都会对数据返回格式进行统一的处理&#xff0c;这样可以方便前端人员取数据&#xff0c;当然除了正常流程的数据返回格式需要统一以外&#xff0c;我们也需要对异常的情况进行统一的处理&#xff0c;以及项目必备的日志。 1. 统一返回格式 …

【小沐学GIS】基于C++绘制三维太阳系SolarSystem(OpenGL、glfw、glut)

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第二期3【小沐学GIS】…

深度学习基础之数据操作

深度学习中最常用的数据是张量&#xff0c;对张量进行操作是进行深度学习的基础。以下是对张量进行的一些操作&#xff1a; 首先我们需要先导入相关的张量库torch。 元素构造&#xff08;初始化&#xff09; 使用arange创造一个行向量&#xff0c;也就是0轴&#xff08;0维&a…

LabVIEW 2023下载安装教程,附安装包和工具,免费使用,无套路获取

前言 LabVIEW是一种程序开发环境&#xff0c;提供一种图形化编程方法&#xff0c;可可视化应用程序的各个方面&#xff0c;包括硬件配置、测量数据和调试&#xff0c;同时可以通过FPGA数学和分析选板中的NI浮点库链接访问浮点运算功能库&#xff0c;LabVIEW软件是NI设计平台的…

西圣H1头戴式耳机发布,不止音质惊艳,更有舒适听音体验

近日&#xff0c;深耕智能声学领域多年的 xisem西圣品牌‏‏发布——‏西圣H1头戴式主动降噪蓝牙耳机正式迎来首销。从各个方面来看&#xff0c;这款头戴式耳机展现出了极具颠覆性的创新&#xff0c;不仅在音质和降噪性能上表现出色&#xff0c;更重要的是采用了更加轻巧的佩戴…

使用记事本修复DBC文件问题V3.0

要麻了&#xff0c;竟然写到3.0了。 有个信号解析不出来&#xff0c;同一条报文的其他信号可以正确解析&#xff0c;打开DBC检查&#xff0c;位置长度都是正确的&#xff0c;死活解析不出来。 打开记事本 发现他居然在信号后面加了个回车&#xff0c;就产生了上面这种诡异的情…

js实现九九乘法表

效果图 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script type"text/javascript">// 输出乘法口诀表// document.write () 空格 " " 换行…

微电网优化MATLAB:火鹰优化算法(Fire Hawk Optimizer,FHO)求解微电网优化(提供MATLAB代码)

一、火鹰优化算法FHO 火鹰优化算法&#xff08;Fire Hawk Optimizer&#xff0c;FHO&#xff09;由Mahdi Azizi等人于2022年提出&#xff0c;该算法性能高效&#xff0c;思路新颖。 单目标优化&#xff1a;火鹰优化算法&#xff08;Fire Hawk Optimizer&#xff0c;FHO&#…

QKCP容器平台安装qkcp paas deployment

22年底23年初做的容器云平台的项目&#xff0c;该份是当初实施部署真实生产环境的手册&#xff0c;关键ip和端口已经更改&#xff0c;现贴来给大伙参阅。 x公司qkcp容器平台安装部署手册 目录 x公司qkcp容器平台安装部署手册 1 集群基础环境 3 1.1. 集群规划信息 3 1.2. 标准…

Eclipses安装教程

一、下载开发工具包 1、开发工具包JDK 下载地址链接&#xff1a;https://www.oracle.com/cn/java/technologies/downloads/ 下载教程&#xff1a; 1&#xff09;点击链接&#xff0c;可以跳转到页面 2&#xff09;下滑页面&#xff0c;找到开发工具包 3&#xff09; 记住下载之…

数据库管理Navicat Premium 15

Navicat Premium 15是一款强大的数据库管理和开发工具&#xff0c;支持多种数据库类型&#xff0c;包括MySQL、MariaDB、SQL Server、SQLite、Oracle和PostgreSQL等。它提供了数据可视化、高效的操作、数据同步与备份等功能&#xff0c;以及用户友好的界面。Navicat Premium 15…

【数据库原理】(37)Web与数据库

随着网络的高速发展和网络服务的日趋完善&#xff0c;网络上的信息量呈几何级数增长。为了有效地组织、存储、管理和使用网上的信息&#xff0c;数据库技术被广泛地应用于网络领域。特别是在Internet上&#xff0c;已建立了数以万计的网站&#xff0c;其中大中型网站的后台大多…

2.4 网络层01

2.4 网络层01 2.4.1 网络层概述 网络层的主要任务是实现网络互连&#xff0c;进而实现数据包在各网络之间的传输。 异构网络内部的计算机要想实现通信是不需要实现网络互联的&#xff0c;异构网络之间要想实现通信就必须实现网络互连。 路由器工作在五层协议体系结构的网络…

Android:JNI实战,加载三方库、编译C/C++

一.概述 Android Jni机制让开发者可以在Java端调用到C/C&#xff0c;也是Android应用开发需要掌握的一项重要的基础技能。 计划分两篇博文讲述Jni实战开发。 本篇主要从项目架构上剖析一个Android App如何通过Jni机制加载三方库和C/C文件。 二.Native C Android Studio可…

python一元线性回归sklearn

# -*- coding: utf-8 -*-from sklearn.linear_model import LinearRegression import numpy as np import matplotlib.pyplot as plt# 载入数据 data np.genfromtxt(一元线性回归.csv, delimiter,) x_data data[:,0] y_data data[:,1] plt.scatter(x_data,y_data) plt.show(…

如何本地安装Python Flask并结合内网穿透实现远程开发

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

03--数据库连接池

1、数据库连接池 1.1 JDBC数据库连接池的必要性 在使用开发基于数据库的web程序时&#xff0c;传统的模式基本是按以下步骤&#xff1a; 在主程序&#xff08;如servlet、beans&#xff09;中建立数据库连接进行sql操作断开数据库连接 这种模式开发&#xff0c;存在的问题:…

外贸自建站如何建立?海洋建站的操作指南?

外贸自建站的建站流程什么&#xff1f;做跨境怎么搭建外贸网站&#xff1f; 外贸自建站成为企业开拓国际市场、提升品牌形象的重要途径。然而&#xff0c;对于许多企业而言&#xff0c;如何高效地进行外贸自建站仍然是一个挑战。海洋建站将带您一步步探讨外贸自建站的关键步骤…

Ubuntu重设root的密码

重设root的密码 未重设密码之前&#xff0c;Ubuntu 中默认的 root 密码是随机的&#xff0c;即每次开机都会有一个新的root 密码&#xff0c;所以此时的 root 用户密码并不确定&#xff1b; 重设root 密码&#xff0c;使用安装时创建的用户登录后sudo su切换至root用户&#…

JAVASE进阶(设计模式、设计原则)(更新中...)

目录 一、注解 内置注解&#xff1a;JAVA中已经定义好的注解。 元注解&#xff1a;修饰注解的注解。 自定义注解。 二、克隆 JAVA中对clone的实现&#xff1f; 浅克隆 深克隆 那么该如何做到深克隆呢&#xff1f; 三、常用设计模式 1、创建型模式 单例模式 工厂模式 工…