22天入门设计模式(C++版)

第一、什么是设计模式?

设计模式是软件设计中常见问题的典型解决方案 它们就像能根据需求进行调整的预制蓝图 可用于解决代码中反复出现的设计问题

设计模式与方法或库的使用方式不同 你很难直接在自己的程序中套用某个设计模式 模式并不是一段特定的代码 而是解决特定问题的一般性概念 你可以根据模式来实现符合自己程序实际所需的解决方案

人们常常会混淆模式和算法 因为两者在概念上都是已知特定问题的典型解决方案 但算法总是明确定义达成特定目标所需的一系列步骤 而模式则是对解决方案的更高层次描述 同一模式在两个不同程序中的实现代码可能会不一样

算法更像是菜谱 提供达成目标的明确步骤 而模式更像是蓝图 你可以看到最终的结果和模式的功能 但需要自己确定实现步骤

第二、模式包含哪些内容?

大部分模式都有正规的描述方式 以便在不同情况下使用 模式的描述通常会包括以下部分

  • 意图部分简单描述问题和解决方案
  • 动机部分将进一步解释问题并说明模式会如何提供解决方案
  • 结构部分展示模式的每个部分和它们之间的关系
  • 在不同语言中的实现提供流行编程语言的代码 让读者更好地理解模式背后的思想

部分模式介绍中还列出其他的一些实用细节 例如模式的适用性 实现步骤以及与其他模式的关系

第三、设计模式分类?

  • 创建型模式提供创建对象的机制 增加已有代码的灵活性和可复用性

  • 结构型模式介绍如何将对象和类组装成较大的结构 并同时保持结构的灵活和高效

  • 行为模式负责对象间的高效沟通和职责委派

 

第一、工厂方法模式

(虚拟构造函数、Virtual Constructor、Factory Method)

1.意图

工厂方法模式是一种创建型设计模式 其在父类中提供一个创建对象的方法 允许子类决定实例化对象的类型

2.工厂方法模式结构

 3.工厂方法模式适合应用场景

3.1 当你在编写代码的过程中 如果无法预知对象确切类别及其依赖关系时 可使用工厂方法

3.2 如果你希望用户能扩展你软件库或框架的内部组件 可使用工厂方法

3.3 如果你希望复用现有对象来节省系统资源 而不是每次都重新创建对象 可使用工厂方法

4.工厂方法模式实现方式

  1. 让所有产品都遵循同一接口 该接口必须声明对所有产品都有意义的方法

  2. 在创建类中添加一个空的工厂方法 该方法的返回类型必须遵循通用的产品接口

  3. 在创建者代码中找到对于产品构造函数的所有引用 将它们依次替换为对于工厂方法的调用 同时将创建产品的代码移入工厂方法

    你可能需要在工厂方法中添加临时参数来控制返回的产品类型

    工厂方法的代码看上去可能非常糟糕 其中可能会有复杂的 switch分支运算符 用于选择各种需要实例化的产品类 但是不要担心 我们很快就会修复这个问题

  4. 现在 为工厂方法中的每种产品编写一个创建者子类 然后在子类中重写工厂方法 并将基本方法中的相关创建代码移动到工厂方法中

  5. 如果应用中的产品类型太多 那么为每个产品创建子类并无太大必要 这时你也可以在子类中复用基类中的控制参数

    例如 设想你有以下一些层次结构的类 基类 邮件及其子类 航空邮件 陆路邮件  ​ 运输及其子类 飞机, 卡车 火车  ​ 航空邮件仅使用 飞机对象 而 陆路邮件则会同时使用 卡车 火车对象 你可以编写一个新的子类 (例如 火车邮件  来处理这两种情况 但是还有其他可选的方案 客户端代码可以给 陆路邮件类传递一个参数 用于控制其希望获得的产品

  6. 如果代码经过上述移动后 基础工厂方法中已经没有任何代码 你可以将其转变为抽象类 如果基础工厂方法中还有其他语句 你可以将其设置为该方法的默认行为

5.C++示例代码

#include <iostream>
#include <string>

/**
 * The Product interface declares the operations that all concrete products must
 * implement.
 */

class Product {
public:
	virtual ~Product() {}
	virtual std::string Operation() const = 0;
};

/**
 * Concrete Products provide various implementations of the Product interface.
 */
class ConcreteProduct1 : public Product {
public:
	std::string Operation() const override {
		return "{Result of the ConcreteProduct1}";
	}
};
class ConcreteProduct2 : public Product {
public:
	std::string Operation() const override {
		return "{Result of the ConcreteProduct2}";
	}
};

/**
 * The Creator class declares the factory method that is supposed to return an
 * object of a Product class. The Creator's subclasses usually provide the
 * implementation of this method.
 */

class Creator {
	/**
	 * Note that the Creator may also provide some default implementation of the
	 * factory method.
	 */
public:
	virtual ~Creator() {};
	virtual Product* FactoryMethod() const = 0;
	/**
	 * Also note that, despite its name, the Creator's primary responsibility is
	 * not creating products. Usually, it contains some core business logic that
	 * relies on Product objects, returned by the factory method. Subclasses can
	 * indirectly change that business logic by overriding the factory method and
	 * returning a different type of product from it.
	 */

	std::string SomeOperation() const {
		// Call the factory method to create a Product object.
		Product* product = this->FactoryMethod();
		// Now, use the product.
		std::string result = "Creator: The same creator's code has just worked with " + product->Operation();
		delete product;
		return result;
	}
};

/**
 * Concrete Creators override the factory method in order to change the
 * resulting product's type.
 */
class ConcreteCreator1 : public Creator {
	/**
	 * Note that the signature of the method still uses the abstract product type,
	 * even though the concrete product is actually returned from the method. This
	 * way the Creator can stay independent of concrete product classes.
	 */
public:
	Product* FactoryMethod() const override {
		return new ConcreteProduct1();
	}
};

class ConcreteCreator2 : public Creator {
public:
	Product* FactoryMethod() const override {
		return new ConcreteProduct2();
	}
};

/**
 * The client code works with an instance of a concrete creator, albeit through
 * its base interface. As long as the client keeps working with the creator via
 * the base interface, you can pass it any creator's subclass.
 */
void ClientCode(const Creator& creator) {
	// ...
	std::cout << "Client: I'm not aware of the creator's class, but it still works.\n"
		<< creator.SomeOperation() << std::endl;
	// ...
}

/**
 * The Application picks a creator's type depending on the configuration or
 * environment.
 */

int main() {
	std::cout << "App: Launched with the ConcreteCreator1.\n";
	Creator* creator = new ConcreteCreator1();
	ClientCode(*creator);
	std::cout << std::endl;
	std::cout << "App: Launched with the ConcreteCreator2.\n";
	Creator* creator2 = new ConcreteCreator2();
	ClientCode(*creator2);

	delete creator;
	delete creator2;
	return 0;
}

第二、抽象工厂模式

(Abstract Factory)

1.意图

抽象工厂模式是一种创建型设计模式 它能创建一系列相关的对象 而无需指定其具体类

2.模式结构

3.适合应用场景

3.1 如果代码需要与多个不同系列的相关产品交互 但是由于无法提前获取相关信息 或者出于对未来扩展性的考虑 你不希望代码基于产品的具体类进行构建 在这种情况下 你可以使用抽象工厂

3.2  如果你有一个基于一组抽象方法的类 且其主要功能因此变得不明确 那么在这种情况下可以考虑使用抽象工厂模式

4.实现方式

  1. 以不同的产品类型与产品变体为维度绘制矩阵

  2. 为所有产品声明抽象产品接口 然后让所有具体产品类实现这些接口

  3. 声明抽象工厂接口 并且在接口中为所有抽象产品提供一组构建方法

  4. 为每种产品变体实现一个具体工厂类

  5. 在应用程序中开发初始化代码 该代码根据应用程序配置或当前环境 对特定具体工厂类进行初始化 然后将该工厂对象传递给所有需要创建产品的类

  6. 找出代码中所有对产品构造函数的直接调用 将其替换为对工厂对象中相应构建方法的调用。

5.C++ 示例代码

/**
 * Each distinct product of a product family should have a base interface. All
 * variants of the product must implement this interface.
 */
class AbstractProductA {
 public:
  virtual ~AbstractProductA(){};
  virtual std::string UsefulFunctionA() const = 0;
};

/**
 * Concrete Products are created by corresponding Concrete Factories.
 */
class ConcreteProductA1 : public AbstractProductA {
 public:
  std::string UsefulFunctionA() const override {
    return "The result of the product A1.";
  }
};

class ConcreteProductA2 : public AbstractProductA {
  std::string UsefulFunctionA() const override {
    return "The result of the product A2.";
  }
};

/**
 * Here's the the base interface of another product. All products can interact
 * with each other, but proper interaction is possible only between products of
 * the same concrete variant.
 */
class AbstractProductB {
  /**
   * Product B is able to do its own thing...
   */
 public:
  virtual ~AbstractProductB(){};
  virtual std::string UsefulFunctionB() const = 0;
  /**
   * ...but it also can collaborate with the ProductA.
   *
   * The Abstract Factory makes sure that all products it creates are of the
   * same variant and thus, compatible.
   */
  virtual std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const = 0;
};

/**
 * Concrete Products are created by corresponding Concrete Factories.
 */
class ConcreteProductB1 : public AbstractProductB {
 public:
  std::string UsefulFunctionB() const override {
    return "The result of the product B1.";
  }
  /**
   * The variant, Product B1, is only able to work correctly with the variant,
   * Product A1. Nevertheless, it accepts any instance of AbstractProductA as an
   * argument.
   */
  std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override {
    const std::string result = collaborator.UsefulFunctionA();
    return "The result of the B1 collaborating with ( " + result + " )";
  }
};

class ConcreteProductB2 : public AbstractProductB {
 public:
  std::string UsefulFunctionB() const override {
    return "The result of the product B2.";
  }
  /**
   * The variant, Product B2, is only able to work correctly with the variant,
   * Product A2. Nevertheless, it accepts any instance of AbstractProductA as an
   * argument.
   */
  std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override {
    const std::string result = collaborator.UsefulFunctionA();
    return "The result of the B2 collaborating with ( " + result + " )";
  }
};

/**
 * The Abstract Factory interface declares a set of methods that return
 * different abstract products. These products are called a family and are
 * related by a high-level theme or concept. Products of one family are usually
 * able to collaborate among themselves. A family of products may have several
 * variants, but the products of one variant are incompatible with products of
 * another.
 */
class AbstractFactory {
 public:
  virtual AbstractProductA *CreateProductA() const = 0;
  virtual AbstractProductB *CreateProductB() const = 0;
};

/**
 * Concrete Factories produce a family of products that belong to a single
 * variant. The factory guarantees that resulting products are compatible. Note
 * that signatures of the Concrete Factory's methods return an abstract product,
 * while inside the method a concrete product is instantiated.
 */
class ConcreteFactory1 : public AbstractFactory {
 public:
  AbstractProductA *CreateProductA() const override {
    return new ConcreteProductA1();
  }
  AbstractProductB *CreateProductB() const override {
    return new ConcreteProductB1();
  }
};

/**
 * Each Concrete Factory has a corresponding product variant.
 */
class ConcreteFactory2 : public AbstractFactory {
 public:
  AbstractProductA *CreateProductA() const override {
    return new ConcreteProductA2();
  }
  AbstractProductB *CreateProductB() const override {
    return new ConcreteProductB2();
  }
};

/**
 * The client code works with factories and products only through abstract
 * types: AbstractFactory and AbstractProduct. This lets you pass any factory or
 * product subclass to the client code without breaking it.
 */

void ClientCode(const AbstractFactory &factory) {
  const AbstractProductA *product_a = factory.CreateProductA();
  const AbstractProductB *product_b = factory.CreateProductB();
  std::cout << product_b->UsefulFunctionB() << "\n";
  std::cout << product_b->AnotherUsefulFunctionB(*product_a) << "\n";
  delete product_a;
  delete product_b;
}

int main() {
  std::cout << "Client: Testing client code with the first factory type:\n";
  ConcreteFactory1 *f1 = new ConcreteFactory1();
  ClientCode(*f1);
  delete f1;
  std::cout << std::endl;
  std::cout << "Client: Testing the same client code with the second factory type:\n";
  ConcreteFactory2 *f2 = new ConcreteFactory2();
  ClientCode(*f2);
  delete f2;
  return 0;
}
View Code

 

posted @ 2023-06-20 15:41  kangobs  阅读(14)  评论(0编辑  收藏  举报