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

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

前言

有关设计模式的其他常用模式请参考

单例模式的实现

常见的设计模式(模板与方法,观察者模式,策略模式)


工程方法

定义

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


要点

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


比如连接池、线程池

隐藏对象真实类型;

对象创建会有很多参数来决定如何创建;

创建对象有复杂的依赖关系;

本质

延迟到子类来选择实现;


结构图

78f16e07a597defb410cb0e7e8f39c00_2a0e063e36b343a385edae8fe00bbe1d.png


举例

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


代码

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

其实和工厂方法是类似的,只是在工厂中创建多个对象。


结构图

646719049f33a49a06bf2ff88cd4ac76_38dcc95ca2034543b8820c9b921bbcb4.png


例子

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


代码

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


要点

解耦请求方和处理方,请求方不知道请求是如何被处理,处理方的组成是由相互独- 立的子处理构成,子处理流程通过链表的方式连接,子处理请求可以按任意顺序组合;

责任链请求强调请求最终由一个子处理流程处理;通过了各个子处理条件判断;

责任链扩展就是功能链,功能链强调的是,一个请求依次经由功能链中的子处理流程处理;

将职责以及职责顺序运行进行抽象,那么职责变化可以任意扩展,同时职责顺序也可以任意扩展;

本质

分离职责,动态组合;

结构图

d5b73b0f9cd279a85180f782ab52aeaa_fee44151504a401f820b87fcd4e7a32d.png


例子

请求流程,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;
};
相关文章
|
9天前
|
设计模式 关系型数据库
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
34 15
|
4月前
|
设计模式 XML Java
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
46 0
|
3月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
2月前
|
设计模式 前端开发 JavaScript
前端必须掌握的设计模式——装饰器模式
装饰器模式是一种结构型设计模式,通过创建新类来包装原始对象,实现在不修改原有结构的前提下扩展新行为。其核心在于“组合”思想,使新功能可“即插即拔”。该模式具有解耦性、灵活性和动态性等特点,广泛应用于类的面向对象编程语言中,如JavaScript的注解和TypeScript的写法。示例中,通过装饰器模式为游戏角色动态添加装备,展示了其强大的扩展性和灵活性。
|
5月前
|
设计模式 存储 算法
设计模式——责任链
OA系统的采购审批项目、职责链模式基本介绍、职责链模式解决 OA 系统采购审批项目
设计模式——责任链
|
5月前
|
设计模式 Java
Java设计模式-装饰器模式(10)
Java设计模式-装饰器模式(10)
|
5月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
5月前
|
设计模式 Java
Java设计模式-工厂方法模式(4)
Java设计模式-工厂方法模式(4)
|
6月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
|
6月前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。

热门文章

最新文章