Redian新闻
>
一文讲透设计模式(C++版)

一文讲透设计模式(C++版)

科技

阿里妹导读


本文从设计原则、创建型模式、结构型模式、行为模式四个方向讲述C++的设计模式。

设计原则

单一职责原则

定义:单一职责原则[1],所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。
bad case:IPhone类承担了协议管理(Dial、HangUp)、数据传送(Chat)。

good case:

里式替换原则

定义:里氏代换原则[2](Liskov Substitution Principle LSP),任何基类可以出现的地方,子类一定可以出现。
bad case:ToyGun继承了AbstractGun,但Solider在调用KillEnemy()时会报错(ToyGun无法KillEnemy),即ToyGun无法完全行使AbstractGun的职责。

good case:AbstractToy中将声音、形状都委托给AbstractGun处理。
如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替。

依赖倒置原则

定义:依赖倒置原则[3](Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
bad case:Driver强依赖于奔驰车。

good case:

接口隔离原则

定义:接口隔离原则[4],客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上
bad case:星探寻找美女的类图,其中IpettyGirl过于庞大,容纳过多可变的因素。

good case:通过拆分接口,提高了灵活性、可维护性。

迪米特法则

定义:迪米特法则[5](Law of Demeter)又叫作最少知识原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。
bad case:Teacher要求GroupLeader清点女生的数量,这里Teacher不应该依赖于Gril。

good case:

开闭原则

定义:开闭原则[6],在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”。
以一个书店售书类图为例,当在书店要增加一个打折操作时。
  • bad case:修改实现类,在IBook上增加一个方法GetOffPrice()
  • good case:通过扩展实现变化,增加一个子类OffNovelBook

创建型模式

工厂方法

定义一个用于创建对象的接口Product* CreateProduct(),让子类决定实例化哪一个类。工厂方法模式让类的实例化延迟到子类中进行,从而避免了在父类中创建对象时出现类名称紧耦合的问题,同时提高了代码的可扩展性和可维护性。(工厂方法的好处就是解耦,当我们修改了具体的类,对调用方而言完全不用修改)

class Product {    // 抽象产品public:  virtual void Method() = 0;};class ConcreteProduct1 : public Product {public:  void Method() { cout << "ConcreteProduct1" << endl; }};class ConcreteProduct2 : public Product {public:  void Method() { cout << "ConcreteProduct2" << endl; }};
class Factory { // 抽象工厂public: virtual Product* CreateProduct() = 0;};class ConcreteFactory1 : public Factory {public: Product* CreateProduct() {return new ConcreteProduct1(); }};class ConcreteFactory2 : public Factory {public: Product* CreateProduct() {return new ConcreteProduct2(); }};
int main () { Factory *factory1 = new ConcreteFactory1(); Factory *factory2 = new ConcreteFactory2(); Product *product1 = factory1->CreateProduct(); Product *product2 = factory2->CreateProduct(); product1->Method(); product2->Method();}

抽象工厂

为创建一组相关或相互依赖的对象提供一个接口,而且无须指定他们的具体类。(工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。抽象工厂模式主要用来实现生产一系列的产品。)

class AbstractProductA { public:  virtual ~AbstractProductA(){};  virtual std::string FunctionA() const = 0;};
class ProductA1 : public AbstractProductA { public: std::string FunctionA() const override { return "The result of the product A1."; }};
class ProductA2 : public AbstractProductA { std::string FunctionA() const override { return "The result of the product A2."; }};
class AbstractProductB { public: virtual ~AbstractProductB(){}; virtual std::string FunctionB() const = 0;};
class ProductB1 : public AbstractProductB { public: std::string FunctionB() const override { return "The result of the product B1."; }};
class ProductB2 : public AbstractProductB { public: std::string FunctionB() const override { return "The result of the product B2."; }};
class AbstractFactory { public: virtual AbstractProductA *CreateProductA() const = 0; virtual AbstractProductB *CreateProductB() const = 0;};
class Factory1 : public AbstractFactory { public: AbstractProductA *CreateProductA() const override { return new ProductA1(); } AbstractProductB *CreateProductB() const override { return new ProductB1(); }};
class Factory2 : public AbstractFactory { public: AbstractProductA *CreateProductA() const override { return new ProductA2(); } AbstractProductB *CreateProductB() const override { return new ProductB2(); }};
void Client(const AbstractFactory &factory) { const AbstractProductA *productA = factory.CreateProductA(); const AbstractProductB *productB = factory.CreateProductB(); std::cout << productA->FunctionA() << "\n"; std::cout << productB->FunctionB() << "\n"; delete productA; delete productB;}
int main() { Factory1 *f1 = new Factory1(); Client(*f1); delete f1; Factory2 *f2 = new Factory2(); Client(*f2); delete f2; return 0;}

生成器/建造者

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。(建造者模式关注的是零件类型和装配工艺(顺序))

class Product1{public:    std::vector<std::string> mParts;    void ListParts()const{        std::cout << "Product parts: ";        for (size_t i=0;i<mParts.size();i++){            if(mParts[i]== mParts.back()){ std::cout << mParts[i];            }else{ std::cout << mParts[i] << ", "; }        }        std::cout << "\n\n";     }};
class Builder{ public: virtual ~Builder(){} virtual void ProducePartA() const = 0; virtual void ProducePartB() const = 0; virtual void ProducePartC() const = 0;};
class ConcreteBuilder1 : public Builder{ Product1* mProduct;public: ConcreteBuilder1(){ Reset(); } ~ConcreteBuilder1(){ delete mProduct; }
void Reset() { mProduct = new Product1(); } void ProducePartA()const override{ this->mProduct->mParts.push_back("PartA1"); } void ProducePartB()const override{ this->mProduct->mParts.push_back("PartB1"); } void ProducePartC()const override{ this->mProduct->mParts.push_back("PartC1"); }
Product1* GetProduct() { Product1* result= mProduct; Reset(); return result; }};
class Director { Builder* mbuilder;public: void set_builder(Builder* builder){ mbuilder = builder; }
void BuildMinimalViableProduct(){ mbuilder->ProducePartA(); }
void BuildFullFeaturedProduct(){ mbuilder->ProducePartA(); mbuilder->ProducePartB(); mbuilder->ProducePartC(); }};
void ClientCode(Director& director){ ConcreteBuilder1* builder = new ConcreteBuilder1(); director.set_builder(builder); std::cout << "Standard basic product:\n"; director.BuildMinimalViableProduct();
Product1* p= builder->GetProduct(); p->ListParts(); delete p;
std::cout << "Standard full featured product:\n"; director.BuildFullFeaturedProduct();
p= builder->GetProduct(); p->ListParts(); delete p;
// Remember, the Builder pattern can be used without a Director class. std::cout << "Custom product:\n"; builder->ProducePartA(); builder->ProducePartC(); p=builder->GetProduct(); p->ListParts(); delete p; delete builder;}
int main(){ Director* director= new Director(); ClientCode(*director); delete director; return 0; }

原型

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。(原型模式实现的是一个Clone 接口,注意是接口,也就是基于多态的 Clone 虚函数。)
class Prototype { protected:  string mPrototypeName;  float mPrototypeField;
public: Prototype() {} Prototype(string prototypeName) : mPrototypeName(prototypeName) { } virtual ~Prototype() {} virtual Prototype *Clone() const = 0; virtual void Function(float prototype_field) { this->mPrototypeField = prototype_field; std::cout << "Call Function from " << mPrototypeName << " with field : " << prototype_field << std::endl; }};
class ConcretePrototype1 : public Prototype {private: float mConcretePrototypeField;
public: ConcretePrototype1(string prototypeName, float concretePrototypeField) : Prototype(prototypeName), mConcretePrototypeField(concretePrototypeField) { }
Prototype *Clone() const override { return new ConcretePrototype1(*this); }};
class ConcretePrototype2 : public Prototype {private: float mConcretePrototypeField;
public: ConcretePrototype2(string prototypeName, float concretePrototypeField) : Prototype(prototypeName), mConcretePrototypeField(concretePrototypeField) { } Prototype *Clone() const override { return new ConcretePrototype2(*this); }};
class PrototypeFactory {private: std::unordered_map<Type, Prototype *, std::hash<int>> mPrototypes;
public: PrototypeFactory() { mPrototypes[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f); mPrototypes[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f); }
~PrototypeFactory() { delete mPrototypes[Type::PROTOTYPE_1]; delete mPrototypes[Type::PROTOTYPE_2]; }
Prototype *CreatePrototype(Type type) { return mPrototypes[type]->Clone(); }};
void Client(PrototypeFactory &prototypeFactory) { std::cout << "Let's create a Prototype 1\n"; Prototype *prototype = prototypeFactory.CreatePrototype(Type::PROTOTYPE_1); prototype->Function(90); delete prototype;
std::cout << "Let's create a Prototype 2 \n"; prototype = prototypeFactory.CreatePrototype(Type::PROTOTYPE_2); prototype->Function(10); delete prototype;}
int main() { PrototypeFactory *prototypeFactory = new PrototypeFactory(); Client(*prototypeFactory); delete prototypeFactory;
return 0;}

单例

单例模式是指在整个系统生命周期内,保证一个类只能产生一个实例,确保该类的唯一性
class SingleInstance{public:    static SingleInstance* GetInstance();    void Print();private:    // 构造、析构、拷贝构造和赋值构造均为私有,防止构造多个对象    SingleInstance();    ~SingleInstance();    SingleInstance(const SingleInstance &instance);    const SingleInstance &operator=(const SingleInstance &instance);
static SingleInstance* mInstancePtr;};SingleInstance* SingleInstance::mInstancePtr = nullptr;SingleInstance* SingleInstance::GetInstance(){ if (mInstancePtr == nullptr) mInstancePtr = new SingleInstance(); return mInstancePtr;}

扩展:
  • 在2/3例模式(一个类能够产生2-3个实例)的情况下,则在私有属性内定义一个类的List,List内包含了所有的实例。

  • 在普通类的情况下,想实现单例模式。可以实现一个Manager管理类,Manager类在初始化时生成各个普通类的实例,然后通过GetInstance()统一返回实例。

结构型模式

适配器

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式是一个补偿模式,或者说是一个“补救”模式,通常用来解决接口不相容的问题。
class Target {  // Target,客户期望的接口,可以使具体或抽象的类,也可以是接口public:    virtual void Request() = 0;    virtual ~Target(){};};
class Adaptee { // 需适配的类public: void SpecificRequest() { cout << "Adaptee" << endl; }};
class Adapter : public Target { // 通过内部包装一个Adaptee对象,把源接口转换为目标接口:private: Adaptee* mAdaptee;public: Adapter() { mAdaptee = new Adaptee(); } void Request() { mAdaptee->SpecificRequest(); } // 调用Request()方法会转换成调用adaptee.SpecificRequest() ~Adapter() { delete mAdaptee; }};
int main() { Target* target = new Adapter(); target->Request();
delete target; return 0;}

说明:

  • Target:客户期待的接口

  • Adapter:通过在内部包装一个Adaptee对象,把源接口转换成目标接口

  • Adaptee:需要适配的类

桥接/桥梁

将抽象和实现解耦,使得两者可以独立的变化。
class OperationSys{public:  OperationSys() {}  ~OperationSys(){}
virtual void SetName() = 0; virtual void OutputName() = 0;
protected: std::string mName;};
class IOSSystem:public OperationSys{public: IOSSystem() {} ~IOSSystem() {} virtual void SetName() { mName = "IOS-SYS"; } virtual void OutputName() { std::cout << "I am IOS,name:" << mName << std::endl; }};
class HarmonySystem :public OperationSys{public: HarmonySystem() {} ~HarmonySystem() {} virtual void SetName() { mName = "HarmonySystem"; } virtual void OutputName() { std::cout << "I am Harmony operation system,name:" << mName << std::endl; }};
class AndroidSystem :public OperationSys{public: AndroidSystem() {} ~AndroidSystem() {} virtual void SetName() { mName = "AndroidSystem"; } virtual void OutputName() { std::cout << "I am Android operation system,name:" << mName << std::endl; }};
class Phone{public: Phone() {} ~Phone(){}
virtual void SetName() = 0; virtual void OutputName() = 0; virtual void SetOperation(OperationSys* sys) { mOperSystem = sys; } virtual void OutputSysName() = 0;
protected: OperationSys* mOperSystem; std::string mName;};
class IPhone :public Phone{public: IPhone() {} ~IPhone(){}
virtual void SetName() { mName = "IPhone"; } virtual void OutputName() { std::cout << "I am IPhone,Name:" << mName << std::endl; } virtual void SetOperation(OperationSys* sys) { mOperSystem = sys; } virtual void OutputSysName() { mOperSystem->OutputName(); }};
class HwPhone :public Phone{public: HwPhone() {} ~HwPhone() {}
virtual void SetName() { mName = "HuaWeiPhone"; } virtual void OutputName() { std::cout << "I am HuaWei,Name:" << mName << std::endl; } virtual void SetOperation(OperationSys* sys) { mOperSystem = sys; } virtual void OutputSysName() { mOperSystem->OutputName(); }};
class MiPhone :public Phone{public: MiPhone() {} ~MiPhone() {}
virtual void SetName() { mName = "MiPhone"; } virtual void OutputName() { std::cout << "I am XiaoMi,Name:" << mName << std::endl; } virtual void SetOperation(OperationSys* sys) { mOperSystem = sys; } virtual void OutputSysName() { mOperSystem->OutputName(); }};
int main(int argc, char* argv[]){ IOSSystem* iSys = new IOSSystem(); iSys->SetName(); IPhone* iPhone = new IPhone(); iPhone->SetName(); iPhone->SetOperation(iSys);
HarmonySystem* hSys = new HarmonySystem(); hSys->SetName(); HwPhone* wPhone = new HwPhone(); wPhone->SetName(); wPhone->SetOperation(hSys);
AndroidSystem* aSys = new AndroidSystem(); aSys->SetName(); MiPhone* mPhone = new MiPhone(); mPhone->SetName(); mPhone->SetOperation(aSys);
iPhone->OutputName(); iPhone->OutputSysName();
wPhone->OutputName(); wPhone->OutputSysName();
mPhone->OutputName(); mPhone->OutputSysName();
return 0;}

说明:

  • Abstraction:抽象化角色,主要职责是定义一个角色的行为,同时保存一个对实现化角色的引用,一般为抽象类

  • Implementor:实现化角色,接口或抽象类,定义角色必须的行为和属性

  • RefinedAbstraction:修正抽象化角色,引用实现化角色对抽象化角色进行修正

  • ConcreteImplementor:具体实现化角色,实现接口或抽象类定义的方法和属性

组合

用来描述部分与整体的关系(将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性)
使用场景:
  1. 希望表示对象的部分-整体层次结构

  2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象

class Component{protected:  string mName;
public: Component(string name) : mName(name) {} virtual ~Component() {} virtual void Operation() = 0; virtual void Add(Component *com) = 0; virtual void Remove(Component *com) = 0; virtual Component *Getchild(int index) = 0; virtual string GetName() { return mName; } virtual void ShowChilds() = 0;};
class Leaf : public Component // 树叶结构{public: Leaf(string name) : Component(name) {} void Operation() { cout << "name : " << mName << endl; }
void Add(Component *com) {} void Remove(Component *com) {} Component *GetChild(int index) { return NULL; } void ShowChilds() {}};
class Composite : public Component // 树枝结构{private: vector<Component *> mComponents;
public: Composite(string name) : Component(name) {} ~Composite() { for (auto &it : mComponents) { cout << "---delete" << it->GetName() + "---" << endl; delete it; it = nullptr; } mComponents.clear(); } void Operation() { cout << "我是 " << mName << endl; } void Add(Component *com) { mComponents.push_back(com); } void Remove(Component *com){ for (auto &it : mComponents) { for (auto it = mComponents.begin(); it != mComponents.end(); ++it) { if (*it != nullptr && (*it)->GetName() == com->GetName()) { delete *it; *it = nullptr; mComponents.erase(it); break; } } } } Component *Getchild(int index){ if ((size_t)index > mComponents.size()) return nullptr; return mComponents[index - 1]; }
void ShowChilds(){ for (auto it = mComponents.begin(); it != mComponents.end(); ++it) { cout << (*it)->GetName() << endl; } }};

说明:

  • Component:抽象构件角色

  • Leaf:叶子构件,遍历的最小单位

  • Composite:树枝构件,组合树枝节点和叶子节点形成一个树形结构

装饰

动态地给一个对象添加一些额外的职责(用来给对象增加某些特性或者对被装饰对象进行某些修改)。装饰模式是继承关系的一个替代方案,但多层的装饰是比较复杂的。
class Component {public:  virtual ~Component() {};  virtual void Operate() = 0;};
class ConcreteComponent : public Component{public: void Operate() override { cout << "do something" << endl;}};
class Decorator : public Component{public: Decorator(Component* component) : mComponent(component) {} void Operate() override{ mComponent->Operate(); }private: Component* mComponent = nullptr;};
class ConcreteDecorator1 : public Decorator {public: ConcreteDecorator1(Component* component) : Decorator(component) {}
void Operate() override { method1(); Decorator::Operate(); }private: void method1() { cout << "method1 修饰" << endl; }};
class ConcreteDecorator2 : public Decorator {public: ConcreteDecorator2(Component* component) : Decorator(component) {}
void Operate() override { method2(); Decorator::Operate(); }private: void method2() { cout << "method2 修饰" << endl; }};
int main(){ Component* component = new ConcreteComponent(); component = new ConcreteDecorator1(component); component = new ConcreteDecorator2(component); component->Operate(); delete component;}

说明:

  • Component抽象构件

  • ConcreteComponent具体构件,需要装饰的对象

  • Decorator装饰角色,属性中必然有一个private变量指向Component抽象构件

  • 具体装饰角色(ConcreteDecoratorA、ConcreteDecoratorB)

外观/门面

门面模式要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。简单地说,门面对象是外界访问子系统内部的唯一通道,不管系统内部是多么杂乱无章,只要门面对象在,就可以做到“金玉其外,败絮其中”。
class A{public:void DoSomething() { cout << "class A is doing something" << endl; }};
class B{public:void DoSomething() { cout << "class B is doing something" << endl; }};
class C{public:void DoSomething() { cout << "class C is doing something" << endl; }};
class Facade{public:Facade(){ a = make_shared<A>(); b = make_shared<B>(); c = make_shared<C>();}
void DoSomething(){ a->DoSomething(); b->DoSomething(); c->DoSomething();}
private:shared_ptr<A> a;shared_ptr<B> b;shared_ptr<C> c;};
int main(){ Facade facade; facade.DoSomething();}

说明:
  • Facade门面角色,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就是说该角色没有实际的业务逻辑,只是一个委托类。
  • subsystem子系统角色,子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。

享元

享元模式是池技术的重要实现方式(使用共享对象可有效地支持大量细粒度的对象)。享元模式的目在于运用共享技术,使得一些细粒度的对象可以共享
享元模式将细粒度的对象信息分为两部分:内部状态(intrinsic,对象可共享的信息存储在享元对象内部且不随环境而改变),外部状态(extrinsic,对象依赖的标记随环境而改变)。
class Flyweight{public:  // 享元角色必须接受外部状态  Flyweight(const string& extrinsic) : mExtrinsic(extrinsic) {}  virtual void Operate() = 0;  string GetIntrinsic() { return mIntrinsic; }  void SetIntrinsic(const string& extrinsic) { mIntrinsic = extrinsic; }
protected: const string mExtrinsic; // 外部状态
private: string mIntrinsic; // 内部状态};
class ConcreteFlyweight1 : public Flyweight{public: ConcreteFlyweight1(const string& extrinsic) : Flyweight(extrinsic) {} void Operate() override { cout << "ConcreteFlyweight1: " << mExtrinsic << endl; }};
class ConcreteFlyweight2 : public Flyweight{public: ConcreteFlyweight2(const string& extrinsic) : Flyweight(extrinsic) {} void Operate() override { cout << "ConcreteFlyweight2: " << mExtrinsic << endl; }};
class FlyweightFactory{public: static shared_ptr<Flyweight> GetFlyweight(const string& extrinsic) { shared_ptr<Flyweight> flyweight; if (mPool.find(extrinsic) != mPool.end()) { flyweight = mPool[extrinsic]; } else { flyweight = make_shared<ConcreteFlyweight1>(extrinsic); mPool.emplace(extrinsic, flyweight); } return flyweight; }
private: static unordered_map<string, shared_ptr<Flyweight>> mPool; };
unordered_map<string, shared_ptr<Flyweight>> FlyweightFactory::mPool{};
int main(){ FlyweightFactory::GetFlyweight("extrinsic1"); FlyweightFactory::GetFlyweight("extrinsic2"); shared_ptr<Flyweight> flyweight = FlyweightFactory::GetFlyweight("extrinsic2"); flyweight->SetIntrinsic("intrinsic2"); flyweight->Operate(); return 0;}

说明:

  • Flyweight 抽象享元角色,定义对象的外部、内部状态的接口。

  • ConcreteFlyweight 具体享元角色,实现抽象角色定义的业务。

  • unsharedConcreteFlyweight 不可共享的享元角色,不存在外部状态或安全要求(线程安全)不能够使用共享技术的对象,一般不出现在享元工厂中。

  • FlyweightFactory 享元工厂,构造一个池容器,同时提供从池中获得对象的方法。

代理/委托

代理模式为其他对象提供一种代理以控制对这个对象的访问。
在设计模式中又可分为普通代理和强制代理:
  • 普通代理:客户端只能访问代理角色,而不能访问真实角色
  • 强制代理:从真实角色查找到代理角色,不允许直接访问真实角色。

class Subject{public:  virtual void Request() = 0;};
class RealSubject : public Subject{public: void Request() override { cout << "RealSubject is doing something" << endl;}};
class Proxy : public Subject{public: Proxy(Subject* subject) : mSubject(subject) {} void Request() override { Before(); mSubject->Request(); After(); }
private: void Before() { cout << "preparing ..." << endl; } void After() { cout << "Finishing ..." << endl; }
Subject* mSubject;};
int main(){ Subject* realSubject = new RealSubject(); Proxy proxy(realSubject); proxy.Request(); return 0;}
说明:
  • Subject 抽象主题角色。
  • RealSubjuect 具体主题角色,业务逻辑的具体执行者。
  • Proxy 代理主题角色(委托类、代理类),负责对真实角色的应用。(也可以在真实角色处理完毕前后做预处理善后处理工作)

行为模式

责任链

责任链模式使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有对象处理它为止。
在实际应用中,一般会有一个封装类对责任模式进行封装,也就是替代Client类,直接返回链中第一个处理者,具体链的设置不需要高层次模块关系。
class Handler{public:  virtual ~ Handler() {}  void HandleRequest(int32_t requestLevel){    if (GetHandlerLevel() == requestLevel)    {      DoSomething();    }    else    {      if (mNextHandler)      {        mNextHandler->HandleRequest(requestLevel);      }      else      {        cout << "can not find request handler" << endl;      }    }  }  void SetNextHandler(Handler* handler){    mNextHandler = handler;  }  virtual int32_t GetHandlerLevel() = 0;  virtual void DoSomething() = 0;
private: Handler* mNextHandler;};
class ConcreteHandler1 : public Handler{public: int32_t GetHandlerLevel() override { return 1; } void DoSomething() override { cout << "ConcreteHandler1 is doing something" << endl;}};
class ConcreteHandler2 : public Handler{public: int32_t GetHandlerLevel() override { return 2; } void DoSomething() override { cout << "ConcreteHandler2 is doing something" << endl;}};
class ConcreteHandler3 : public Handler{public: int32_t GetHandlerLevel() override { return 3; } void DoSomething() override { cout << "ConcreteHandler3 is doing something" << endl;}};
int main(){ Handler* handler1 = new ConcreteHandler1(); Handler* handler2 = new ConcreteHandler2(); Handler* handler3 = new ConcreteHandler3(); handler1->SetNextHandler(handler2); handler2->SetNextHandler(handler3); handler1->HandleRequest(4); delete handler1; delete handler2; delete handler3; return 0;}

说明:
  • Handler 抽象处理者
  • ConcreteHandler 具体的处理者

命令

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者请求日志,可以提供撤销和恢复功能。
class Receiver{public:    virtual void DoSomething() = 0;};
class ConcreteReceiver1 : public Receiver{public: void DoSomething() override { std::cout << "ConcreteReceiver1 is doing something" << std::endl; }};
class ConcreteReceiver2 : public Receiver{public: void DoSomething() override { std::cout << "ConcreteReceiver2 is doing something" << std::endl; }};
class Command{public: Command(const std::shared_ptr<Receiver>& receiver) : mReceiver(receiver) {} virtual void Execute() = 0;
protected: std::shared_ptr<Receiver> mReceiver;};
class ConcreteCommand1 : public Command{public: ConcreteCommand1(const std::shared_ptr<Receiver>& receiver) : Command(receiver) {}
void Execute() override { mReceiver->DoSomething(); }};
class ConcreteCommand2 : public Command{public: ConcreteCommand2(const std::shared_ptr<Receiver>& receiver) : Command(receiver) {}
void Execute() override { mReceiver->DoSomething(); }};
class Invoker{public: void SetCommand(const std::shared_ptr<Command>& command) { mCommand = command; } void Action() { mCommand->Execute(); }
private: std::shared_ptr<Command> mCommand;};
int main(){ std::shared_ptr<Receiver> receiver1(new ConcreteReceiver1()); std::shared_ptr<Command> command1(new ConcreteCommand1(receiver1));
Invoker invoker; invoker.SetCommand(command1); invoker.Action();
return 0;}

说明:

  • Receive接收者角色 该角色就是干活的角色,命令传递到这里是应该被执行的。

  • Command命令角色 需要执行的所有命令都在这里声明。

  • Invoker调用者角色 接受命令,并执行命令。

这样调用者角色(Invoker)与接受者角色(Receiver)之间没有任何关系,调用者实现功能时只需要调用Command抽象类的execute方法就可以,不需要到底是哪个接受者执行,实现了类间解耦
这样Command的子类可以非常容易扩展(可扩展性),调用者Invoker和高层次模块Client不产生严重的代码耦合。

迭代器

迭代器模式提供一种方法访问一个容器对象中各个元素,而不需要暴露该对象的内部细节。
迭代器模式目前已经是一个没落的模式,因为随着现代编程语言的发展和标准库的丰富,使用迭代器模式的场景变得越来越少。
在C++中可以使用STL库提供的迭代器,例如使用vector容器的迭代器来遍历容器内的元素。此外,C++也支持自定义迭代器,开发者可以根据具体需求实现自己的迭代器。自定义迭代器需要实现相应的迭代器接口,例如begin、end、operator++等,以及重载解引用运算符(*)和箭头运算符(->)等。

中介者

用一个中介者封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散。
在多个对象依赖的情况下,通过加入中介者角色,取消了多个对象的关联或依赖关系,减少了对象的耦合性。相对的中介者会膨胀的很大,同事类越多中介者逻辑越复杂。
class Mediator;class Colleague{public:    Colleague(const shared_ptr<Mediator>& mediator) : mMediator(mediator) {};protected:    shared_ptr<Mediator> mMediator;};class ConcreteColleague1 : public Colleague{public:    ConcreteColleague1(const shared_ptr<Mediator>& mediator) : Colleague(mediator) {}    void SelfMethod() { cout << "ConcreteColleague1 处理自己的业务逻辑" << endl; }    void DepMethod() { cout << "ConcreteColleague1 委托中介者处理" << endl; }};class ConcreteColleague2 : public Colleague{public:    ConcreteColleague2(const shared_ptr<Mediator>& mediator) : Colleague(mediator) {}    void SelfMethod() { cout << "ConcreteColleague2 处理自己的业务逻辑" << endl; }    void DepMethod() { cout << "ConcreteColleague2 委托中介者处理" << endl; }};class Mediator{public:    shared_ptr<ConcreteColleague1> GetC1() { return mConcreteColleague1; }    void SetC1(const shared_ptr<ConcreteColleague1>& concreteColleague1) { mConcreteColleague1 = concreteColleague1; }    shared_ptr<ConcreteColleague2> GetC2() { return mConcreteColleague2; }    void SetC2(const shared_ptr<ConcreteColleague2>& concreteColleague2) { mConcreteColleague2 = concreteColleague2; }    virtual void DoSomething1()=0;    virtual void DoSomething2()=0;protected:    shared_ptr<ConcreteColleague1> mConcreteColleague1;    shared_ptr<ConcreteColleague2> mConcreteColleague2;};class ConcreteMediator : public Mediator{public:    void DoSomething1() override {        mConcreteColleague1->SelfMethod();        mConcreteColleague2->SelfMethod();    }    void DoSomething2() override{        mConcreteColleague2->DepMethod();        mConcreteColleague2->DepMethod();    }};
int main(){ shared_ptr<ConcreteMediator> mediator(new ConcreteMediator); shared_ptr<ConcreteColleague1> C1(new ConcreteColleague1(mediator)); shared_ptr<ConcreteColleague2> C2(new ConcreteColleague2(mediator));
mediator->SetC1(C1); mediator->SetC2(C2); // 调用中介者的操作 mediator->DoSomething1(); mediator->DoSomething2();
return 0;}

同事类使用构造函数注入中介者,而中介者使用get/set方法注入同事类,是因为同事类必须有中介者,而中介者可以只有部分同事类。

说明:
  • Mediator抽象中介者角色 定义统一接口,用于各同事角色之间的通信。

  • Concrete Mediator具体中介者角色 通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。

  • Colleague同事角色 每一个同事角色都知道中介者角色,而且与其他同事角色通信时,一定要通过中介者角色协作。

备忘录

备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
使用场景:需要保存和恢复数据的相关状态场景;需要提供可回滚操作;需要监控的副本场景。
class Memento{public:    Memento() {}    Memento(string state) :mState(state) {}    const string& GetState() { return mState; }    void SetState(const string& state) { mState = state; }private:    string mState;};
class Originator{public: const string& GetState() { return mState; } void SetState(const string& state) { mState = state; } Memento CreateMemento() { return Memento(mState); } void Restore(Memento memento) { SetState(memento.GetState()); }private: string mState;};
class Caretaker{public: Memento& GetMemento() { return mMemento; } void SetMemento(Memento memento) { mMemento = memento; }private: Memento mMemento;};
int main(){ Originator originator; originator.SetState("state1"); Caretaker caretaker; caretaker.SetMemento(originator.CreateMemento()); originator.SetState("state2"); originator.Restore(caretaker.GetMemento()); cout << "current state: " << originator.GetState() << endl; return 0;}
说明:
  • Originator 发起人角色,记录当前内部状态,负责创建恢复备忘录数据

  • Memento 备忘录角色,负责存储Originator发起人对象的内部状态,需要时提供发起人需要的内部状态

  • Caretaker 备忘录管理员角色,对备忘录进行管理、保存和提供备忘录

观察者

也称为发布-订阅模式。定义对象间的一种一对多的依赖关系,当一个对象(可观察对象)的状态发生改变时,所有依赖于它的对象(观察者)都得到通知并被自动更新。
class Observer {public:  virtual void Update(string &context) = 0;};
class Observer1 : public Observer {public: void Update(string &context) override { cout << "observer1 get message: " + context << endl; }};
class Observer2 : public Observer {public: void Update(string &context) override { cout << "observer2 get message: " + context << endl; }};
class Observable {public: virtual void AddObserver(Observer *observer) = 0; virtual void DeleteObserver(Observer *observer) = 0; virtual void NotifyObserver() = 0;};
class Subject : public Observable {public: string GetState() { return mContext; }; void SetState(string context) { mContext = context; }; void AddObserver(Observer *observer) override { mObserverList.push_back(observer); }; void DeleteObserver(Observer *observer)override { mObserverList.remove(observer); }; void NotifyObserver() override { for (const auto& it : mObserverList) it->Update(mContext); };private: list<Observer *> mObserverList; string mContext;};
void Client() { Subject *subject = new Subject; Observer *observer1 = new Observer1(); Observer *observer2 = new Observer2(); subject->AddObserver(observer1); subject->AddObserver(observer2);
subject->SetState("I'm doing something"); subject->NotifyObserver();}
int main() { Client(); return 0;}

输出:

observer1 get message: I'm doing something
observer2 get message: I'm doing something

扩展:根据应用场景的不同,观察者模式会对应不同的代码实现方式:有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式观察者模式应用场景[7]
.

监听器

也称为回调模式。它使用回调函数来处理事件,当事件发生时,它会调用预先定义的回调函数来响应事件。这种模式通常用于异步编程,例如事件驱动编程或GUI编程。虽然观察者模式和监听器模式具有相似的特性,但它们的目的和实现方式略有不同。观察者模式通常用于实现对象之间的通信和协作,而监听器模式则更侧重于事件处理和异步编程。

状态

状态模式就是当一个对象内在状态改变时,允许其改变行为,这个对象看起来像改变了其类。
使用场景:行为随状态改变而改变的场景;条件、分支判断语句的替代者。
class State;class Context{public:    Context();    void SetState(State* state);    State* GetState1();    State* GetState2();    State* GetState();    void Handle1();    void Handle2();private:    State* mState1;    State* mState2;    State* mCurrentState;};
class State{public: State(Context* context) : mContext(context) {} virtual void Handle1() = 0; virtual void Handle2() = 0;protected: Context* mContext;};class ConcreteState1 : public State{public: ConcreteState1(Context* context) : State(context) {} void Handle1() override { cout << "ConcreteState1 is doing something" << endl; }; void Handle2() override{ mContext->SetState(mContext->GetState2()); }};
class ConcreteState2 : public State{public: ConcreteState2(Context* context) : State(context) {} void Handle1() override { cout << "ConcreteState2 is doing something" << endl; }; void Handle2() override{ mContext->SetState(mContext->GetState1()); }};
Context::Context() : mState1(new ConcreteState1(this)), mState2(new ConcreteState2(this)), mCurrentState(mState1) {}void Context::SetState(State* state) { mCurrentState = state; }State* Context::GetState1() { return mState1; }State* Context::GetState2() { return mState2; }State* Context::GetState() { return mCurrentState; }void Context::Handle1() { mCurrentState->Handle1(); }void Context::Handle2() { mCurrentState->Handle2(); }
int main(){ Context context; context.Handle1(); // do something context.Handle2(); // switch to state 2 context.Handle1(); // do something context.Handle2(); // switch to state 1 return 0;}

说明:

  • State 抽象状态角色,负责对象状态定义,并且封装环境角色以实现状态切换

  • ConcreteState 具体状态角色,需实现当前状态下的行为管理以及状态的转变

  • Context 环境角色,负责具体状态的切换

策略

定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
使用场景:多个类只有在算法或行为上有所不同;算法需要自由切换;需要屏蔽算法规则。
class Strategy{public:    virtual void DoSomething() = 0;};class ConcreteStrategy1 : public Strategy{public:    void DoSomething() override { cout << "ConcreteStrategy1 is doing something" << endl; }};class ConcreteStrategy2 : public Strategy{public:    void DoSomething() override { cout << "ConcreteStrategy2 is doing something" << endl; }};class Context{public:    Context(Strategy* strategy) : mStrategy(strategy) {}    void DoAnything() { mStrategy->DoSomething(); } private:    Strategy* mStrategy;};
int main(){ Strategy* strategy = new ConcreteStrategy1(); Context context(strategy); context.DoAnything();}

说明:

  • Context 封装角色,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化

  • Strategy 抽象策略角色,策略、算法的抽象

  • ConcreteStrategy 具体策略角色,实现抽象策略中的操作

模板方法

定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该肃反的某些特定步骤。
模板方法模式可以说是继承思想的一种应用,但并不是完全等同于继承。
class AbstractClass{public:    virtual void DoSomething() = 0;    virtual void DoAnything() = 0;    void TemplateMethod(){        DoSomething();        DoAnything();    }};class ConcreteClass1 : public AbstractClass{public:    void DoSomething() override { cout << "ConcreteClass1 is doing something" << endl; }    void DoAnything() override { cout << "ConcreteClass1 is doing anything" << endl; }};class ConcreteClass2 : public AbstractClass{public:    void DoSomething() override { cout << "ConcreteClass2 is doing something" << endl; }    void DoAnything() override { cout << "ConcreteClass2 is doing anything" << endl; }};
int main(){ AbstractClass* class1 = new ConcreteClass1(); AbstractClass* class2 = new ConcreteClass2(); class1->TemplateMethod(); class2->TemplateMethod();}

说明:模版方法模式中方法分为两类

  • 基本方法,由子类实现
  • 模版方法,一个框架实现对基本方法的调度,完成固定的逻辑

访问者

封装一下作用于某种数据结构中的各元素的操作,他可以在不改变数据结构的前提下作用于这些元素的新的操作。
使用场景:需要遍历多个不同的对象,它们有不同的接口(迭代器只能访问同类/接口)。
访问者模式是对迭代器模式的扩充,可以遍历不同的对象,然后执行不同的操作。
class Visitor;class Element {public:    virtual void Accept(Visitor& v) = 0;};class ConcreteElementA : public Element {public:    void Accept(Visitor& v) override;    void OperationA();};class ConcreteElementB : public Element {public:    void Accept(Visitor& v) override;    void OperationB();};
class Visitor {public: virtual void visit(ConcreteElementA& e) = 0; virtual void visit(ConcreteElementB& e) = 0;};class ConcreteVisitor1 : public Visitor {public: void visit(ConcreteElementA& e) override{ cout << "visit "; e.OperationA(); cout << endl; } void visit(ConcreteElementB& e) override{ cout << "visit "; e.OperationB(); cout << endl; }};
class ConcreteVisitor2 : public Visitor {public: void visit(ConcreteElementA& e) override{ // 访问 ConcreteElementA 的另一个操作 cout << "visit "; e.OperationA(); cout << " in another way" << endl; } void visit(ConcreteElementB& e) override{ // 访问 ConcreteElementB 的另一个操作 cout << "visit "; e.OperationB(); cout << " in another way" << endl; }};
void ConcreteElementA::Accept(Visitor& v) { v.visit(*this); }void ConcreteElementA::OperationA() { cout << "ConcreteElementA"; }void ConcreteElementB::Accept(Visitor& v) { v.visit(*this); }void ConcreteElementB::OperationB() { cout << "ConcreteElementB"; }class ObjectStructure{public: static Element* CreateElement(){ if (rand() % 100 > 50) { return new ConcreteElementA(); } else { return new ConcreteElementB(); } }};int main(){ ConcreteVisitor1 visitor1; ConcreteVisitor2 visitor2; for (int i=0; i < 10; i++) { Element* e = ObjectStructure::CreateElement(); e->Accept(visitor1); e->Accept(visitor2); }}

说明:

  • Vistor 抽象访问者,声明访问者可以访问哪些元素

  • ConcreteVistor 具体访问者,影响访问者访问到一个类后该干什么

  • Element 抽象角色,声明接受那一类访问者访问

  • ConcreteElement 具体元素,实现accept方法

  • ObjectStructure 结构对象,元素生产者,一般容纳在多个不同类、接口的容器(vector、map)

参考:

《设计模式之禅》
refactoring-设计模式分类:https://refactoringguru.cn/design-patterns/
看懂UML类图和时序图:https://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#id2

30分钟学会UML类图:https://zhuanlan.zhihu.com/p/109655171

[1]:https://baike.baidu.com/item/单一职责原则/9456515
[2]:https://baike.baidu.com/item/里氏代换原则/3104388?lemmaFrom=lemma_starMap&fromModule=lemma_starMap
[3]https://baike.baidu.com/item/依赖倒置原则/6189149?lemmaFrom=lemma_starMap&fromModule=lemma_starMap
[4]https://baike.baidu.com/item/接口隔离原则/3104602?lemmaFrom=lemma_starMap&fromModule=lemma_starMap
[5]https://baike.baidu.com/item/迪米特法则/2107000?structureClickId=2107000&structureId=294b5d3c8cc7452ad5c9cdba&structureItemId=6a0cd5ee9cda2b44038895ee&lemmaFrom=starMapContent&fromModule=starMap_content
[6]https://baike.baidu.com/item/开闭原则/2828775?structureClickId=2828775&structureId=294b5d3c8cc7452ad5c9cdba&structureItemId=d59481c0283e288f9b31e60f&lemmaFrom=starMapContent&fromModule=starMap_content

[7]https://blog.51cto.com/u_12279910/4217867#_1


阿里云开发者社区,千万开发者的选择


阿里云开发者社区,百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,欢迎点击【阅读原文】加入我们。


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
调节心理状态的80种方式(值得收藏)黄子平:读中文系的人|鲁迅人文讲座预告《东风第一枝 - 谷雨》香港“户口”大放水,要冲吗?一文讲明白高才通和优才通!深度探讨乳腺癌中HER2表达模式(下篇)工改后,事业单位职务有哪些变化?一文讲清楚(附对比图)【探索】有趣+炫酷+清凉,用新晋“顶流”运动打开消暑新方式(内附场地推荐)全网最齐全的设计模板库,有了!一文讲清楚楼市未来半年基本趋势一文讲透!小红书营销组件及评论区组件闭环收割玩法!深度探讨乳腺癌中HER2表达模式(上篇)活动预告丨科技引领 未来无限:清华经管未来科技首届年度峰会暨未来科技校友会成立仪式(附直播通道)旺自己的3种方式(渡了无数人)消逝的背影改变自己最好的方式(此文无价)痛心!又是5名少年溺亡!一文讲透溺水,守护孩子的夏天ICLR 2023邀你加入精选论文讲解直播间一文讲透财务分析的思路和技巧改变自己最好的方式(深度好文)一文讲透:信息流广告的“玄学”与“科学”一位北大才子的"润"之路揭晓!2023德国 IF 最佳产品设计金奖作品新鲜出炉!(完整版)全网最新最齐全的设计模板,已经为你整理好了!丛京生院士ICCAD大会万字演讲:讲透民主化集成电路设计与可定制计算知名主播确认离世,事发前一天还在直播,生前最后一文讲述童年遭遇霸凌用EA中文讲义,69天当美国注册税务师!​为了你走遍草原 第八章MVRDV设计模块化办公楼,每个区域都可拆卸硬膜穿刺后头痛,一文讲清发生机制、危险因素、治疗及预防免费领 | 剑桥彩虹少儿英语分级阅读外教中英文讲解录播课90集,让孩子一步步从无到有,掌握阅读技巧!一文讲透品牌如何玩转明星&达人营销年纪轻轻就脱发?有一种自救方式(不是植发)2023美国婚姻绿卡怎么申请?一文讲透!《薔薇處處開》活动预告 | 数据赋能城市转型,打造数字地产新范式(5.12@上海)
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。