学校网站源码开源,苏州做企业网站,北京注册公司核名网站,微信网页制作网站一、设计模式前言 设计模式#xff08;Design Patterns#xff09;的“模式”指的是一种在软件设计中经过验证的、解决特定问题的方案。它们不是具体的代码#xff0c;而是解决常见设计问题的抽象方案或模板。设计模式提供了一种标准的方式来组织代码#xff0c;以提高代码…一、设计模式前言 设计模式Design Patterns的“模式”指的是一种在软件设计中经过验证的、解决特定问题的方案。它们不是具体的代码而是解决常见设计问题的抽象方案或模板。设计模式提供了一种标准的方式来组织代码以提高代码的重用性、可维护性和可扩展性。 设计模式通常包括以下几个方面 问题Problem描述在特定上下文中需要解决的设计问题。解决方案Solution提供一种或多种解决该问题的方法。效果Consequences说明采用该模式后可能会带来的优点和缺点。 《Design Patterns: Elements of Reusable Object-Oriented Software》通常被称为《Gang of Four》GoF一书是设计模式领域的经典之作。这本书将设计模式分为三大类 创建型模式如单例模式、工厂模式、建造者模式等主要解决对象创建问题。结构型模式如适配器模式、装饰器模式、桥接模式等主要解决类或对象的组合问题。行为型模式如观察者模式、策略模式、状态模式等主要解决对象间的通信和职责分配问题。 每种设计模式都有其特定的应用场景通过使用这些模式开发者能够更有效地管理复杂的系统设计 二、设计模式基本原则
设计模式的最高目标应当是高内聚、低耦合 高内聚High Cohesion 定义高内聚指的是一个模块或类的职责应该高度集中即模块或类应当完成单一且明确的功能。 特点 职责单一一个模块或类应该只关注于完成某一个具体的功能或职责避免过多的职责分散在一个模块中。功能相关模块内部的功能和数据是紧密相关的这样可以使得模块更加专注和稳定。 好处 易于理解和维护一个模块应当只负责自己的职责 低耦合Low Coupling 定义低耦合指的是一个模块或类与其他模块或类之间的依赖关系应该尽可能少互相之间的影响最小化。 特点 独立性强一个模块的实现和变化不应该影响到其他模块模块之间的交互通过清晰的接口进行。接口明确模块之间的通信应该通过接口或抽象类来实现具体实现细节对外部隐藏。 好处 灵活性高低耦合使得各个模块可以独立开发、测试和维护增强了系统的灵活性。易于扩展当需要增加新的功能或替换某个模块时可以不影响其他模块降低了改动的风险。增强可复用性低耦合的模块更容易在不同的上下文中复用因为它们不依赖于特定的实现或其他模块的内部结构 在软件设计中实现“高内聚、低耦合”的目标可以使系统更加健壮、易于维护和扩展。高内聚确保了每个模块专注于自己的职责而低耦合则减少了模块之间的依赖增强了系统的灵活性和可维护性。这两个原则目标通常被视为良好软件设计的基石。
三、设计模式的7种基本原则
1开放封闭原则OCPOpen for Extension,Closed for Modification Principle
模块/类的变化是通过增加功能代码实现的非修改源代码。即“软件实体如类、模块、函数等应该对扩展开放对修改封闭。”
实现OCP常用方法 使用抽象和接口通过抽象类或接口定义模块的核心功能然后使用具体的实现类来扩展功能。这样你可以在不修改原有代码的情况下添加新的实现类来扩展功能。 使用设计模式 策略模式Strategy Pattern可以通过定义策略接口和不同的策略实现来实现功能的扩展而不修改现有的代码。装饰器模式Decorator Pattern允许你通过包装现有的对象来添加新的功能而不改变原有对象的代码。模板方法模式Template Method Pattern通过定义一个算法的骨架并允许子类重写某些步骤从而实现功能的扩展。
设计模式后面会详细讲述这里使用代码简单演示下OCP的方法。
// 模拟银行业务代码功能实现的迭代符合开放封闭原则 对扩展开放代码允许通过增加新的派生类如autoTransferAccountsWorker 、autoPayWorker和autoDepositWorker 来扩展业务功能而不需要修改现有的BankWorker类及其子类。这符合开放封闭原则中“对扩展开放”的要求。 对修改封闭代码的设计避免了对现有类如BankWorker和已有的业务类进行修改。只需创建新的业务类并实现 doWorking() 方法即可扩展功能。这也符合开放封闭原则中“对修改封闭”的要求。
ocp.cpp
#include iostream
using namespace std;class BankWork
{
public:void deposit(){std::cout 存款: std::endl;}void transferAccounts(){std::cout 转账: std::endl;}void pay(){std::cout 缴费: std::endl;}
protected:
private:
};class BankWorker : public BankWork
{
public:virtual void doWorking() 0;
};//已存在的业务
class DepositWorker : public BankWorker
{
public:virtual void doWorking(){std::cout 存款: std::endl;}
};class transferAccountsWorker : public BankWorker
{
public:virtual void doWorking(){std::cout 转账: std::endl;}
};class PayWorker : public BankWorker
{
public:virtual void doWorking(){std::cout 缴费: std::endl;}
};//扩展业务
class autoTransferAccountsWorker : public BankWorker
{
public:virtual void doWorking(){std::cout 批量转账: std::endl;}
};class autoPayWorker : public BankWorker
{
public:virtual void doWorking(){std::cout 批量缴费: std::endl;}
};//又一个新扩展的业务
class autoDepositWorker : public BankWorker
{
public:virtual void doWorking(){std::cout 批量存款: std::endl;}
};//传统的业务调用
void main001()
{BankWork *ptr new BankWork ;ptr-deposit();ptr-transferAccounts();ptr-pay();delete ptr;std::cout 传统的业务调用完成! std::endl;return ;
}//新的业务调用
void main002()
{BankWorker *new_ptr NULL;new_ptr new DepositWorker;new_ptr-doWorking(); //有多态发生delete new_ptr;new_ptr new transferAccountsWorker;new_ptr-doWorking(); //有多态发生delete new_ptr;new_ptr new PayWorker;new_ptr-doWorking(); //有多态发生delete new_ptr;std::cout 新的业务调用完成! std::endl;return ;
}//框架函数
void howDo(BankWorker *ptr)
{ptr-doWorking(); //有多态发生
}//扩展业务调用
void main003()
{BankWorker *new_ptr NULL;new_ptr new autoTransferAccountsWorker;howDo(new_ptr);delete new_ptr;new_ptr new autoPayWorker;howDo(new_ptr);delete new_ptr;new_ptr new autoDepositWorker;howDo(new_ptr);delete new_ptr;std::cout 扩展业务调用完成! std::endl;return ;
}
int main()
{
//调用业务main001();main002();main003();
}
运行效果 2依赖倒置原则DIPDependence Inversion Principle
依赖于抽象的接口不依赖具体的实现类/模块即依赖于接口编程其核心思想是高层模块不应该依赖于低层模块。两者都应该依赖于抽象。抽象不应该依赖于细节。细节应该依赖于抽象。
实现DIP常用方法 使用接口或抽象类将高层模块和低层模块的依赖关系抽象化。例如定义一个接口或抽象类低层模块实现这个接口而高层模块依赖于这个接口。 依赖注入Dependency Injection通过构造函数注入、方法注入或属性注入等方式将依赖项传递给需要它们的类从而使高层模块和低层模块之间的依赖关系变得松散。
DIP的示例 Bankworker类依赖于 DepositInterface、TransferAccountsInterface 和 PayInterface 接口而不是具体的实现类。这样BankWorker可以使用任何实现了这些接口的类。 具体实现类仍然是 DepositWorker、TransferAccountsWorker 和 PayWorker。这些实现类可以独立开发和测试不需要修改BankWorker。 依赖注入则通过构造函数将具体的实现类传递给 BankWorker。这样BankWorker 不再直接创建具体的实现对象而是通过接口来使用它们。 howDo 函数用于处理扩展业务它仍然依赖于接口这样可以处理不同的具体实现而不需要修改其代码。
dip.cpp
#include iostream
#include memory// 业务接口
class DepositInterface
{
public:virtual ~DepositInterface() default;virtual void deposit() const 0;
};class TransferAccountsInterface
{
public:virtual ~TransferAccountsInterface() default;virtual void transferAccounts() const 0;
};class PayInterface
{
public:virtual ~PayInterface() default;virtual void pay() const 0;
};// 高层模块业务处理器
class BankWorker
{
public:BankWorker(std::unique_ptrDepositInterface depositImpl,std::unique_ptrTransferAccountsInterface transferImpl,std::unique_ptrPayInterface payImpl): depositImpl(std::move(depositImpl)),transferImpl(std::move(transferImpl)),payImpl(std::move(payImpl)) {}void deposit() const{depositImpl-deposit();}void transferAccounts() const{transferImpl-transferAccounts();}void pay() const{payImpl-pay();}private:std::unique_ptrDepositInterface depositImpl;std::unique_ptrTransferAccountsInterface transferImpl;std::unique_ptrPayInterface payImpl;
};// 具体实现类
class DepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 存款: std::endl;}
};class TransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 转账: std::endl;}
};class PayWorker : public PayInterface
{
public:void pay() const override{std::cout 缴费: std::endl;}
};// 扩展业务处理器
class AutoTransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 批量转账: std::endl;}
};class AutoPayWorker : public PayInterface
{
public:void pay() const override{std::cout 批量缴费: std::endl;}
};class AutoDepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 批量存款: std::endl;}
};// 框架函数
templatetypename T
void howDo(const std::unique_ptrT ptr)
{if constexpr (std::is_base_ofDepositInterface, T::value) {ptr-deposit();}if constexpr (std::is_base_ofTransferAccountsInterface, T::value) {ptr-transferAccounts();}if constexpr (std::is_base_ofPayInterface, T::value) {ptr-pay();}
}// 传统的业务调用
void main001()
{BankWorker worker(std::make_uniqueDepositWorker(),std::make_uniqueTransferAccountsWorker(),std::make_uniquePayWorker());worker.deposit();worker.transferAccounts();worker.pay();std::cout 传统的业务调用完成! std::endl;
}// 扩展业务调用
void main002()
{std::unique_ptrAutoTransferAccountsWorker autoTransferWorker std::make_uniqueAutoTransferAccountsWorker();howDo(autoTransferWorker);std::unique_ptrAutoPayWorker autoPayWorker std::make_uniqueAutoPayWorker();howDo(autoPayWorker);std::unique_ptrAutoDepositWorker autoDepositWorker std::make_uniqueAutoDepositWorker();howDo(autoDepositWorker);std::cout 扩展业务调用完成! std::endl;
}int main()
{main001();main002();return 0;
}
运行效果 3迪米特法则LoDLaw of Demeter
迪米特法则又被称为最少知识原则不要和陌生人说话原则一个对象/模块应当对其他对象/模块尽可能的不了解以降低各个对象/模块之间的耦合关系整体提高系统的可维护性、健壮性。
LoD的核心要点 每个对象应当只与其直接的朋友对象通信。换句话说方法只能调用 对象的自身的方法。作为参数传递进来的对象的方法。对象创建的例如通过构造函数或工厂方法对象的方法。对象的成员变量成员变量应当是该类的内部实现的一部分。 避免链式调用。即对象 A 不应直接调用对象 B 的方法然后再通过对象 B 调用对象 C 的方法。这样会使得对象 A 对对象 C 的实现细节产生依赖从而增加耦合度。
实现LoD常用方法 封装数据将数据和操作数据的方法封装在一个类中尽量减少外部对这些数据的直接访问。 使用接口通过接口定义模块之间的交互而不是直接操作对象的内部状态。 控制方法访问范围尽量将方法和数据的访问范围控制在最小的范围内。例如使用私有private或保护protected访问修饰符来限制访问
LoD的示例
1、设置函数howDo(const T obj)为操作对象的引用或指针避免直接对具体实现类的操作
2、设置BankWorker 设计为只与接口 DepositInterface、TransferAccountsInterface 和 PayInterface 交互而不是具体的实现类。
lod.cpp
#include iostream
#include memory// 业务接口
class DepositInterface
{
public:virtual ~DepositInterface() default;virtual void deposit() const 0;
};class TransferAccountsInterface
{
public:virtual ~TransferAccountsInterface() default;virtual void transferAccounts() const 0;
};class PayInterface
{
public:virtual ~PayInterface() default;virtual void pay() const 0;
};// 高层模块业务处理器
class BankWorker
{
public:BankWorker(std::unique_ptrDepositInterface depositImpl,std::unique_ptrTransferAccountsInterface transferImpl,std::unique_ptrPayInterface payImpl): depositImpl(std::move(depositImpl)),transferImpl(std::move(transferImpl)),payImpl(std::move(payImpl)) {}void deposit() const{depositImpl-deposit();}void transferAccounts() const{transferImpl-transferAccounts();}void pay() const{payImpl-pay();}private:std::unique_ptrDepositInterface depositImpl;std::unique_ptrTransferAccountsInterface transferImpl;std::unique_ptrPayInterface payImpl;
};// 具体实现类
class DepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 存款: std::endl;}
};class TransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 转账: std::endl;}
};class PayWorker : public PayInterface
{
public:void pay() const override{std::cout 缴费: std::endl;}
};// 扩展业务处理器
class AutoTransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 批量转账: std::endl;}
};class AutoPayWorker : public PayInterface
{
public:void pay() const override{std::cout 批量缴费: std::endl;}
};class AutoDepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 批量存款: std::endl;}
};// 框架函数
templatetypename T
void howDo(const T obj)
{if constexpr (std::is_base_ofDepositInterface, T::value) {obj.deposit();}if constexpr (std::is_base_ofTransferAccountsInterface, T::value) {obj.transferAccounts();}if constexpr (std::is_base_ofPayInterface, T::value) {obj.pay();}
}// 传统的业务调用
void main001()
{BankWorker worker(std::make_uniqueDepositWorker(),std::make_uniqueTransferAccountsWorker(),std::make_uniquePayWorker());worker.deposit();worker.transferAccounts();worker.pay();std::cout 传统的业务调用完成! std::endl;
}// 扩展业务调用
void main002()
{std::unique_ptrAutoTransferAccountsWorker autoTransferWorker std::make_uniqueAutoTransferAccountsWorker();howDo(*autoTransferWorker);std::unique_ptrAutoPayWorker autoPayWorker std::make_uniqueAutoPayWorker();howDo(*autoPayWorker);std::unique_ptrAutoDepositWorker autoDepositWorker std::make_uniqueAutoDepositWorker();howDo(*autoDepositWorker);std::cout 扩展业务调用完成! std::endl;
}int main()
{main001();main002();return 0;
} 运行效果 4单一职责原则SRPSingle Responsibility Principle
类/模块职责功能要单一即对外尽可能的只提供一种功能也希望引起功能变化的原因只有一个。SRP的核心思想是一个类应该只有一个原因引起它的变化。
SRP的好处
提高代码的可维护性如果一个类只承担一个职责当这个职责发生变化时只需要修改这个类减少了对其他部分的影响。增强代码的可读性单一职责的类通常更小、更专注易于理解和阅读。提高代码的可重用性职责单一的类可以在其他项目中更容易地复用因为它的功能和行为更明确。简化测试职责明确的类更容易进行单元测试因为它们的行为更集中和专一
SRP的示例 分离处理类BankWorker 被拆分为 DepositProcessor、TransferProcessor 和 PayProcessor。每个处理器类负责一种业务操作的处理。 具体业务类具体的实现类如 DepositWorker 和 AutoDepositWorker直接传递给处理器类。
srp.cpp
#include iostream
#include memory// 业务接口
class DepositInterface
{
public:virtual ~DepositInterface() default;virtual void deposit() const 0;
};class TransferAccountsInterface
{
public:virtual ~TransferAccountsInterface() default;virtual void transferAccounts() const 0;
};class PayInterface
{
public:virtual ~PayInterface() default;virtual void pay() const 0;
};// 具体实现类
class DepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 存款: std::endl;}
};class TransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 转账: std::endl;}
};class PayWorker : public PayInterface
{
public:void pay() const override{std::cout 缴费: std::endl;}
};// 扩展业务实现类
class AutoDepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 批量存款: std::endl;}
};class AutoTransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 批量转账: std::endl;}
};class AutoPayWorker : public PayInterface
{
public:void pay() const override{std::cout 批量缴费: std::endl;}
};// 业务处理器
class DepositProcessor
{
public:DepositProcessor(std::unique_ptrDepositInterface depositImpl): depositImpl(std::move(depositImpl)) {}void process() const{depositImpl-deposit();}private:std::unique_ptrDepositInterface depositImpl;
};class TransferProcessor
{
public:TransferProcessor(std::unique_ptrTransferAccountsInterface transferImpl): transferImpl(std::move(transferImpl)) {}void process() const{transferImpl-transferAccounts();}private:std::unique_ptrTransferAccountsInterface transferImpl;
};class PayProcessor
{
public:PayProcessor(std::unique_ptrPayInterface payImpl): payImpl(std::move(payImpl)) {}void process() const{payImpl-pay();}private:std::unique_ptrPayInterface payImpl;
};// 传统的业务调用
void main001()
{DepositProcessor depositProcessor(std::make_uniqueDepositWorker());TransferProcessor transferProcessor(std::make_uniqueTransferAccountsWorker());PayProcessor payProcessor(std::make_uniquePayWorker());depositProcessor.process();transferProcessor.process();payProcessor.process();std::cout 传统的业务调用完成! std::endl;
}// 扩展业务调用
void main002()
{DepositProcessor depositProcessor(std::make_uniqueAutoDepositWorker());TransferProcessor transferProcessor(std::make_uniqueAutoTransferAccountsWorker());PayProcessor payProcessor(std::make_uniqueAutoPayWorker());depositProcessor.process();transferProcessor.process();payProcessor.process();std::cout 扩展业务调用完成! std::endl;
}int main()
{main001();main002();return 0;
}
运行效果 5接口隔离原则ISPInterface Segregation Principle
一个类不应被迫依赖它不使用的方法。换句话说一个接口应当尽可能地保持简单和专注避免将过多的职责集中在一个接口上。
ISP的核心思想是客户端不应该依赖于它不需要的接口。
ISP的好处
减少耦合当接口被拆分成多个小接口时每个客户端只依赖于它所需要的部分减少了不必要的依赖。提高灵活性系统中的类只实现它们需要的接口易于进行修改和扩展。增强可维护性小的接口通常更简单易于理解和维护。提升可重用性小接口具有明确的责任可以在不同的上下文中重用。
接口隔离原则的主要目标是避免“胖接口”fat interface即一个接口包含过多的方法。
实现ISP的常用方法
分析接口的职责识别接口中的不同职责将它们拆分成多个小的接口。定义专注的接口创建专注于单一功能的小接口以减少不必要的依赖。采用组合通过接口的组合来实现复杂的功能而不是将所有功能放在一个接口中。避免接口膨胀避免将过多的方法放在一个接口中保持接口的简单性和专注性。
ISP的示例 接口设计将BankWorker类拆分为多个接口DepositInterface、TransferAccountsInterface、PayInterface这样每个接口只包含一个特定的业务功能。符合接口隔离原则提高了代码的灵活性和可维护性。
isp.cpp
#include iostream
#include memory// 基类
class BankWork
{
public:virtual ~BankWork() default;virtual void deposit() const{std::cout 存款: std::endl;}virtual void transferAccounts() const{std::cout 转账: std::endl;}virtual void pay() const{std::cout 缴费: std::endl;}
};// 业务接口
class DepositInterface
{
public:virtual ~DepositInterface() default;virtual void deposit() const 0;
};class TransferAccountsInterface
{
public:virtual ~TransferAccountsInterface() default;virtual void transferAccounts() const 0;
};class PayInterface
{
public:virtual ~PayInterface() default;virtual void pay() const 0;
};// 业务处理类
class BankWorker : public DepositInterface, public TransferAccountsInterface, public PayInterface
{
public:virtual ~BankWorker() default;void deposit() const override{std::cout 存款: std::endl;}void transferAccounts() const override{std::cout 转账: std::endl;}void pay() const override{std::cout 缴费: std::endl;}
};// 业务处理器
class DepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 存款: std::endl;}
};class TransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 转账: std::endl;}
};class PayWorker : public PayInterface
{
public:void pay() const override{std::cout 缴费: std::endl;}
};// 扩展业务
class AutoTransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 批量转账: std::endl;}
};class AutoPayWorker : public PayInterface
{
public:void pay() const override{std::cout 批量缴费: std::endl;}
};class AutoDepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 批量存款: std::endl;}
};// 框架函数
templatetypename T
void howDo(const std::unique_ptrT ptr)
{// 先检查 T 是否实现了相关接口if constexpr (std::is_base_ofDepositInterface, T::value) {ptr-deposit();}if constexpr (std::is_base_ofTransferAccountsInterface, T::value) {ptr-transferAccounts();}if constexpr (std::is_base_ofPayInterface, T::value) {ptr-pay();}
}// 传统的业务调用
void main001()
{std::unique_ptrBankWorker ptr std::make_uniqueBankWorker();ptr-deposit();ptr-transferAccounts();ptr-pay();std::cout 传统的业务调用完成! std::endl;
}// 新的业务调用
void main002()
{std::unique_ptrDepositWorker depositWorker std::make_uniqueDepositWorker();depositWorker-deposit();std::unique_ptrTransferAccountsWorker transferWorker std::make_uniqueTransferAccountsWorker();transferWorker-transferAccounts();std::unique_ptrPayWorker payWorker std::make_uniquePayWorker();payWorker-pay();std::cout 新的业务调用完成! std::endl;
}// 扩展业务调用
void main003()
{std::unique_ptrAutoTransferAccountsWorker autoTransferWorker std::make_uniqueAutoTransferAccountsWorker();howDo(autoTransferWorker);std::unique_ptrAutoPayWorker autoPayWorker std::make_uniqueAutoPayWorker();howDo(autoPayWorker);std::unique_ptrAutoDepositWorker autoDepositWorker std::make_uniqueAutoDepositWorker();howDo(autoDepositWorker);std::cout 扩展业务调用完成! std::endl;
}int main()
{main001();main002();main003();return 0;
}
运行效果 6里氏替换原则LSPLiskov Substitution Principle
如果 S 是 T 的子类型那么在程序中的对象类型 T 替换为 S 时程序的行为不应发生变化。换句话说子类对象应当能够替换掉父类对象而不改变程序的正确性。其核心思想是子类对象必须能够替换父类对象而不影响程序的正确性。
LSP的好处
增强可替换性子类可以替代父类增加了系统的灵活性和可扩展性。提高可维护性符合 LSP 的系统设计更容易进行维护和扩展因为子类与基类之间的关系更明确。减少错误遵循 LSP 可以避免在使用子类时出现意外的错误或不一致的行为。增强可靠性系统的行为在替换子类时保持一致提高了系统的可靠性。
实现LSP的常用方法
确保子类的行为符合父类的契约子类应当遵循父类的接口不改变父类方法的预期行为。避免在子类中抛出异常子类的方法不应抛出父类方法未预料的异常。维护一致性子类应当在行为和状态上与父类一致不应引入新的约束或改变已有的约束。使用抽象类或接口当有多个子类有不同的行为时可以使用抽象类或接口来定义通用的功能避免将所有功能放在一个类中。
LSP的示例
创建了一个模板类 Processor它可以用于处理任何实现了 DepositInterface、TransferAccountsInterface 或 PayInterface 的对象。为了使代码保持一致性为每个接口类型专门化了 Processor 类。这样可以确保 Processor 只依赖于基接口并且所有实现类都可以按需替换而不会改变程序的行为。
lsp.cpp
#include iostream
#include memory// 业务接口
class DepositInterface
{
public:virtual ~DepositInterface() default;virtual void deposit() const 0;
};class TransferAccountsInterface
{
public:virtual ~TransferAccountsInterface() default;virtual void transferAccounts() const 0;
};class PayInterface
{
public:virtual ~PayInterface() default;virtual void pay() const 0;
};// 具体实现类
class DepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 存款: std::endl;}
};class TransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 转账: std::endl;}
};class PayWorker : public PayInterface
{
public:void pay() const override{std::cout 缴费: std::endl;}
};// 扩展业务实现类
class AutoDepositWorker : public DepositInterface
{
public:void deposit() const override{std::cout 批量存款: std::endl;}
};class AutoTransferAccountsWorker : public TransferAccountsInterface
{
public:void transferAccounts() const override{std::cout 批量转账: std::endl;}
};class AutoPayWorker : public PayInterface
{
public:void pay() const override{std::cout 批量缴费: std::endl;}
};// 业务处理器
template typename T
class Processor
{
public:Processor(std::unique_ptrT impl) : impl(std::move(impl)) {}void process() const{impl-execute();}private:std::unique_ptrT impl;
};// 处理器特化
template
class ProcessorDepositInterface
{
public:Processor(std::unique_ptrDepositInterface depositImpl): depositImpl(std::move(depositImpl)) {}void process() const{depositImpl-deposit();}private:std::unique_ptrDepositInterface depositImpl;
};template
class ProcessorTransferAccountsInterface
{
public:Processor(std::unique_ptrTransferAccountsInterface transferImpl): transferImpl(std::move(transferImpl)) {}void process() const{transferImpl-transferAccounts();}private:std::unique_ptrTransferAccountsInterface transferImpl;
};template
class ProcessorPayInterface
{
public:Processor(std::unique_ptrPayInterface payImpl): payImpl(std::move(payImpl)) {}void process() const{payImpl-pay();}private:std::unique_ptrPayInterface payImpl;
};// 传统的业务调用
void main001()
{ProcessorDepositInterface depositProcessor(std::make_uniqueDepositWorker());ProcessorTransferAccountsInterface transferProcessor(std::make_uniqueTransferAccountsWorker());ProcessorPayInterface payProcessor(std::make_uniquePayWorker());depositProcessor.process();transferProcessor.process();payProcessor.process();std::cout 传统的业务调用完成! std::endl;
}// 扩展业务调用
void main002()
{ProcessorDepositInterface depositProcessor(std::make_uniqueAutoDepositWorker());ProcessorTransferAccountsInterface transferProcessor(std::make_uniqueAutoTransferAccountsWorker());ProcessorPayInterface payProcessor(std::make_uniqueAutoPayWorker());depositProcessor.process();transferProcessor.process();payProcessor.process();std::cout 扩展业务调用完成! std::endl;
}int main()
{main001();main002();return 0;
}
运行效果 7优先使用组合而非继承原则Favor Composition over Inheritance
在设计类的结构时应该优先考虑使用对象组合的方式来实现功能而不是通过继承来扩展类的功能。 组合Composition 指的是通过将一个类的实例作为另一个类的成员变量来实现功能的复用。例如通过组合将一个对象的功能嵌入到另一个对象中从而实现扩展和复用。 继承Inheritance 是通过创建一个新类子类来扩展或修改已有类父类的功能。子类继承父类的所有公共属性和方法并可以覆盖或扩展它们。 使用组合的好处
减少耦合组合使得类之间的关系更加松散减少了对父类实现细节的依赖从而降低了类之间的耦合度。增强灵活性通过组合可以灵活地改变对象的行为或功能而不需要修改现有的类。它使得系统可以在运行时动态地改变对象的行为。提高可维护性组合比继承更容易进行修改和维护因为更改一个组件的实现通常不会影响到其他组件。避免“继承深度”问题继承可能导致深层次的继承链使得系统复杂度增加而组合可以避免这种情况。 判断是否适合组合的常用方法
识别可复用的功能分析系统中需要复用的功能确定是否可以通过组合来实现这些功能而不是通过继承。使用接口和抽象类通过接口或抽象类定义功能的契约然后通过组合将具体的实现注入到类中。设计模块化的组件将功能划分为独立的组件这些组件可以被组合在一起以实现复杂的功能。避免过度使用继承继承应该仅用于表示“是一个”is-a关系而不是“有一个”has-a关系。对于“有一个”关系组合通常是更合适的选择。
组合的示例
函数对象在Processor中使用std::function来传递具体的业务逻辑。这使得Processor不再依赖具体的实现类。业务逻辑在main001和main002中直接定义了业务逻辑的函数对象这样可以根据需要在代码中灵活地调整行为而不需要创建新的类。
composition.cpp
#include iostream
#include memory
#include functional// 业务接口
class DepositInterface
{
public:virtual ~DepositInterface() default;virtual void deposit() const 0;
};class TransferAccountsInterface
{
public:virtual ~TransferAccountsInterface() default;virtual void transferAccounts() const 0;
};class PayInterface
{
public:virtual ~PayInterface() default;virtual void pay() const 0;
};// 业务处理器
template typename T
class Processor
{
public:Processor(std::functionvoid() func) : func(func) {}void process() const{func();}private:std::functionvoid() func;
};// 传统的业务调用
void main001()
{ProcessorDepositInterface depositProcessor([]() {std::cout 存款: std::endl;});ProcessorTransferAccountsInterface transferProcessor([]() {std::cout 转账: std::endl;});ProcessorPayInterface payProcessor([]() {std::cout 缴费: std::endl;});depositProcessor.process();transferProcessor.process();payProcessor.process();std::cout 传统的业务调用完成! std::endl;
}// 扩展业务调用
void main002()
{ProcessorDepositInterface depositProcessor([]() {std::cout 批量存款: std::endl;});ProcessorTransferAccountsInterface transferProcessor([]() {std::cout 批量转账: std::endl;});ProcessorPayInterface payProcessor([]() {std::cout 批量缴费: std::endl;});depositProcessor.process();transferProcessor.process();payProcessor.process();std::cout 扩展业务调用完成! std::endl;
}int main()
{main001();main002();return 0;
}
运行效果 四、设计模式经典之作
ps:《Design Patterns: Elements of Reusable Object-Oriented Software》一书是一本经典设计模式的作品推荐去看看。Gang of Four书名来源于书籍的四位作者他们分别是
Erich Gamma艾里希·伽玛Richard Helm理查德·赫尔姆Ralph Johnson拉尔夫·约翰逊John Vlissides约翰·弗利西德斯
这四位作者在书中总结并分类了设计模式这本书在软件工程领域中具有重要的影响力因此他们被戏称为《Gang of Four》。这个名字传达了他们在设计模式领域的权威地位并且也带有一种略显俏皮的意味。