23种c++设计模式全解 (设计模式c++第九讲)

点击链接阅读原文,获取更多技术内容: 设计模式(C++版)-阿里云开发者社区

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

作者 | 恒索

来源 | 阿里开发者公众号

设计原则

单一职责原则

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

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

good case:

一文讲透b端产品和c端产品的区别,c++设计模式书籍

里式替换原则

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

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

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

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

依赖倒置原则

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

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

good case:

一文讲透b端产品和c端产品的区别,c++设计模式书籍

接口隔离原则

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

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

迪米特法则

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

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

good case:

一文讲透b端产品和c端产品的区别,c++设计模式书籍

开闭原则

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

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

  • bad case:修改实现类,在IBook上增加一个方法GetOffPrice()
  • good case:通过扩展实现变化,增加一个子类OffNovelBook

一文讲透b端产品和c端产品的区别,c++设计模式书籍

创建型模式

工厂方法

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

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();
}

抽象工厂

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

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;
}

生成器/建造者

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

一文讲透b端产品和c端产品的区别,c++设计模式书籍

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;
}

一文讲透b端产品和c端产品的区别,c++设计模式书籍

单例

单例模式是指在整个系统生命周期内,保证 一个类只能产生一个实例 ,确保该类的 唯一性

剩余60%,完整内容请点击下方链接查看: 设计模式(C++版)-阿里云开发者社区

阿里云开发者社区,千万开发者的选择。百万精品技术内容、千节免费系统课程、丰富的体验场景、活跃的社群活动、行业专家分享交流,尽在:阿里云开发者社区-云计算社区-阿里云