设计模式(C++版)

简介: 看懂UML类图和时序图30分钟学会UML类图设计原则单一职责原则定义:单一职责原则,所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。bad case:IPhone类承担了协议管理(Dial、HangUp)、数据传送(Chat)。good case:里式替换原则定义:里氏代换原则(Liskov 

看懂UML类图和时序图

30分钟学会UML类图

设计原则

单一职责原则

定义单一职责原则,所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因

bad case:IPhone类承担了协议管理(Dial、HangUp)、数据传送(Chat)。

good case

里式替换原则

定义里氏代换原则(Liskov Substitution Principle LSP),任何基类可以出现的地方,子类一定可以出现

bad case:ToyGun(玩具枪)继承了AbstractGun,但Solider在调用KillEnemy()时会报错(ToyGun无法KillEnemy/玩具枪无法杀敌),即ToyGun无法完全行使AbstractGun的职责。

good case:AbstractToy中将声音、形状都委托给AbstractGun处理。

如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替。

依赖倒置原则

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

bad case:Driver强依赖于奔驰车。

good case

接口隔离原则

定义接口隔离原则,客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。

bad case:星探寻找美女的类图,其中IpettyGirl过于庞大,容纳过多可变的因素。

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

迪米特法则

定义迪米特法则(Law of Demeter)又叫作最少知识原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。

bad case:Teacher要求GroupLeader清点女生的数量,这里Teacher不应该依赖于Gril。

good case

开闭原则

定义开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”。

以一个书店售书类图为例,当在书店要增加一个打折操作时。

  • 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

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

监听器

也称为回调模式。它使用回调函数来处理事件,当事件发生时,它会调用预先定义的回调函数来响应事件。这种模式通常用于异步编程,例如事件驱动编程或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-设计模式分类

相关文章
|
4月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
42 3
|
4月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
53 2
|
6月前
|
设计模式 开发框架 算法
C++中的设计模式:基本概念与应用
C++中的设计模式:基本概念与应用
60 2
|
6月前
|
设计模式 算法 中间件
【C++ 可调用对象的应用】C++设计模式与现代编程技巧:深入可调用对象的世界
【C++ 可调用对象的应用】C++设计模式与现代编程技巧:深入可调用对象的世界
211 1
|
6月前
|
设计模式 算法 C++
从 C++ 优化状态机实现:结合设计模式的实用指南
从 C++ 优化状态机实现:结合设计模式的实用指南
519 1
|
6月前
|
设计模式 关系型数据库 数据库
【C++ 设计模式 工厂模式对比】深入探索设计模式:工厂方法与抽象工厂的比较与对照
【C++ 设计模式 工厂模式对比】深入探索设计模式:工厂方法与抽象工厂的比较与对照
66 1
|
6月前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
6月前
|
设计模式 机器学习/深度学习 算法
C++设计模式新篇章:掌握状态委托
C++设计模式新篇章:掌握状态委托
121 0
|
6月前
|
设计模式 存储 安全
C++多线程管理的艺术:从基础到设计模式
C++多线程管理的艺术:从基础到设计模式
103 0
|
6月前
|
设计模式 缓存 编译器
【C/C++ 设计模式应用】精细化职责与灵活性:C++中的发送接口和数据转换基类设计
【C/C++ 设计模式应用】精细化职责与灵活性:C++中的发送接口和数据转换基类设计
108 0