23种设计模式笔记-创建型模式

23种设计模式-创建型模式

笔记模板

模式

  • 前提 - 模式:
  • 概念:
  • 规则:
  • 实现细节:
  • 应用场景:
  • 示意图:
  • 代码实现:

创建型模式

  • 单例、工厂方法、抽象工厂、生成器、原型。

单例模式 - 共享独占资源

  • 概念:创建型设计模式,保证一个类只有一个实例,提供全局访问点来对单个实例进行访问

  • 规则: 私有构造函数,私有静态实例变量,公有静态方法获取实例

  • 实现细节:

    • 饿汉模式: 加载时完成实例创建

    • 懒汉模式: 使用到了再创建(COW),这里在创建的时候需要加锁/进行判断,防止多重创建;

  • 实现场景: 资源共享、只有单个实例、懒加载(lazy)

  • 示意图:
    image

  • 代码: 利用静态实现不可修改性

    c
    	typedef struct _DATA
    	{
    		void* pData;
    	}DATA;
    
    	void* get_data()
    	{
    		static DATA*
    		pData = NULL;
    
    		if(NULL != pData) //这里本质是乐观锁,检查其有没有被修改
    			return pData;
    
    		pData = (DATA*)malloc(sizeof(DATA));
    		assert(NULL != pData); //相同的乐观锁
    		return (void*)pData;
    	}
    
    c++
    	#include <string.h>
    	#include <assert.h>
    
    	class object
    	{
    	public:
    		static class object* pObject;
    
    		static object* create_new_object()
    		{
    			if(NULL != pObject)
    				return pObject;
    
    			pObject = new object();
    			assert(NULL != pObject);
    			return pObject;
    		}
    
    	private:
    		object() {}
    		~object() {}
    	};
    
    	class object* object::pObject = NULL;
    
    	int main(int argc, char* argv[])
    	{
    		object* pGlobal = object::create_new_object();
    		return 1;
    	}
    
      </details>
    

工厂方法模式 - 分离抽象概念与实体

  • 前提 - 简单工厂模式: 将产品的创建过程进行封装,从而封装在一个工厂类中。本质是对相同或者类似方法的封装;

  • 概念: 抽象工厂创建概念 ->具体工厂实现产品创建->创建具体产品->抽象产品接口
    (像Linux的字符驱动设备的创建过程,Linux实现抽象工厂和接口的创建,开发者实现具体工厂和具体产品的创建)

  • 规则: 使用类的集成/结构体+

  • 实现细节: 抽象工厂->具体工厂---链接---具体产品<-抽象产品

  • 应用场景: 每个具体工厂职责单一,创建对象逻辑复杂,且不同的子类创建逻辑不同;核心是隐藏创建产品的细节,避免对源码进行修改

  • 示意图:
    image

  • 代码实现:

    c
    	#include <stdio.h>
    	#include <stdlib.h>
    
    	//定义产品基类
    	// define product interface
    	typedef struct Product {
    		void (*show)(struct Product*);
    	} Product;
    
    	//具体产品创建
    	// define specific productA class
    	typedef struct ProductA {
    		Product product;
    	} ProductA;
    
    	// define productA show function
    	void ProductA_show(Product* product) {
    		printf("This is ProductA\n");
    	}
    
    	// define specific productB class
    	typedef struct ProductB {
    		Product product;
    	} ProductB;
    
    	// define productB show function
    	void ProductB_show(Product* product) {
    		printf("This is ProductB\n");
    	}
    
    	//定义工厂基类
    	// define factory interface
    	typedef struct Factory {
    		Product* (*create_product)(struct Factory*);
    	} Factory;
    
    	//具体工厂创建
    	// define specific factoryA class
    	typedef struct FactoryA {
    		Factory factory;
    	} FactoryA;
    
    	// inplement factoryA create_product function
    	Product* factoryA_create_product(Factory* factory) {
    		Product* product = (Product*)malloc(sizeof(Product));
    		product->show = ProductA_show;
    		return product;
    	}
    
    	// define specific factoryB class
    	typedef struct FactoryB {
    		Factory factory;
    	} FactoryB;
    
    	// inplement factoryB create_product function
    	Product* factoryB_create_product(Factory* factory) {
    		Product* product = (Product*)malloc(sizeof(Product));
    		product->show = ProductB_show;
    		return product;
    	}
    
    	int main() {
    		// 创建类,这里本质是对工厂进行注册,可以使用链表或者数组的形式完成对相应数据结构的存储,从而进一步封装结构
    		//同时,这部分使用了单项绑定链接的方式,即绑定了工厂与产品,并没有绑定产品与工厂,这部分可以修改。
    		// create specific factoryA instance
    		FactoryA FactoryA;
    		FactoryA.factory.create_product = factoryA_create_product;
    
    		// create specific factoryB instance
    		FactoryB FactoryB;
    		FactoryB.factory.create_product = factoryB_create_product;
    		Product* productB = FactoryB.factory.create_product(&FactoryB.factory);
    
    		//这里是直接调用的,但是如果将相应的数据结构加入链表/数组时,其能够实现更好的封装
    		// use specific factory instance create specific product
    		Product* productA = FactoryA.factory.create_product(&FactoryA.factory);
    		productA->show(productA);
    		free(productA);
    
    		// use specific factory instance create specific product
    		Product* productB = FactoryB.factory.create_product(&FactoryB.factory);
    		productB->show(productB);
    		free(productB);
    
    		return 0;
    	}
    
    c++
    /**
     * 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;
    }
    

抽象工厂模式

  • 前提 - 工厂方法模式:

  • 概念: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
    (像Linux的IIC等设备的创建过程,Linux实现抽象工厂和产品类型的创建,开发者实现具体工厂和具体产品的创建)

  • 规则: 使用类的集成/结构体(数据/封装)+函数指针(方法)

  • 实现细节:


    抽象工厂->具体工厂1
    ---链接---
    具体产品A1、具体产品B1


    抽象工厂->具体工厂2
    ---链接---
    具体产品A2、具体产品B2


    具体产品A1、具体产品A2<-抽象产品A
    具体产品B1、具体产品B2<-抽象产品B

  • 应用场景: 问题比较复杂,本质是一个对象需要提供多个产品,且产品的类型是不同的。当产品族中多个产品被放在一起时,客户端使用同一个产品族中的产品,便于增加产品族

  • 示意图:
    image

    • 代码实现:
    c
    #include <stdio.h>
    #include <stdlib.h>
    
    //产品的基类实现
    // productA interface
    typedef struct {
    	void (*show)(char *str);
    } InterfaceProduct;
    
    //具体产品的实现
    // productA class
    typedef struct {
    	InterfaceProduct interfaceProduct;
    } ProductA;
    
    // productB class
    typedef struct {
    	InterfaceProduct interfaceProduct;
    } ProductB;
    
    // 工厂的基类实现
    // abstract factory interface
    typedef struct {
    	void (*createProductA)(ProductA *product);
    	void (*createProductB)(ProductB *product);
    } AbstractFactory;
    
    //具体工厂的实现
    // factory1
    typedef struct {
    	AbstractFactory abstractFactory;
    } ConcreteFactory1;
    
    void createProductA_1(ProductA *product)
    {
    	if (!product) {
    		printf("productA is null\n");
    	return;
    	}
    	product->interfaceProduct.show("ConcreteFactory1 creates ProductA_1\n");
    }
    
    void createProductB_1(ProductB *product)
    {
    	if (!product) {
    		printf("productB is null\n");
    	return;
    	}
    	product->interfaceProduct.show("ConcreteFactory1 creates ProductB_1\n");
    }
    
    ConcreteFactory1 createFactory1()
    {
    	ConcreteFactory1 factory;
    	factory.abstractFactory.createProductA = createProductA_1;
    	factory.abstractFactory.createProductB = createProductB_1;
    	return factory;
    }
    
    // factoryB
    typedef struct {
    	AbstractFactory abstractFactory;
    } ConcreteFactory2;
    
    void createProductA_2(ProductA *product)
    {
    	if (!product) {
    		printf("productA is null\n");
    	return;
    	}
    	product->interfaceProduct.show("ConcreteFactory2 creates ProductA_2\n");
    }
    
    void createProductB_2(ProductB *product)
    {
    	if (!product) {
    		printf("productB is null\n");
    	return;
    	}
    	product->interfaceProduct.show("ConcreteFactory2 creates ProductB_2\n");
    }
    
    ConcreteFactory2 createFactory2()
    {
    	ConcreteFactory2 factory;
    	factory.abstractFactory.createProductA = createProductA_2;
    	factory.abstractFactory.createProductB = createProductB_2;
    	return factory;
    }
    
    //共用函数的抽象
    void common_show(char *str)
    {
    	if (!str) {
    	   printf("str is NULL\n");
    	  return; 
    	}
    
    	printf("%s\n", str);
    }
    
    // client use abstract factory
    void client(AbstractFactory factory) {
    	//客户端(用户层)直接使用相应的同一接口进行调用
    	ProductA productA;
    	productA.interfaceProduct.show = common_show;
    	factory.createProductA(&productA);
    
    	ProductB productB;
    	productB.interfaceProduct.show = common_show;
    	factory.createProductB(&productB);
    }
    
    int main() {
    	//注册相应工厂,传递给客户端
    	ConcreteFactory1 factory1 = createFactory1();
    	ConcreteFactory2 factory2 = createFactory2();
    	client(factory1.abstractFactory);
    	client(factory2.abstractFactory);
    	return 0;
    }
    
    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;
    }
    
    

建造者(生成器)模式

  • 前提 - 工厂方法模式:
  • 概念: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  • 规则: 核心是将复杂对象的创建分步,抽象出步骤(方法)的分类(可以看作不同的工厂)。之后根据步骤,创建指导者对象,对建造进行指导(确定建造的步骤)。其本质是对流程的抽象,便于方法(建造者)的复用
  • 实现细节:
    指导者对象:存放着不同建造者实现的方法(预定义),同时,其也可以直接传入相应的建造者实现,实现客户所需要的建造者
    建造者对象:建造者对象存放着可能建造所需产品的所有方法函数和获取产品的函数
    建造者具体实现:建造者具体实现是基于指导者对象的指导,调用相应的建造者方法,按顺序生产产品
  • 应用场景: 使用代码创建建造过程类似的一系列对象时,或者建造者所建造的对象十分复杂的时候,使用其抽象。类似与Linux使用Kconfig进行配置,预定义的Kconfig是指导者,其中各种驱动程序是建造者,用户在预定义的基础上,通过调整建造者的实现,使建造者生产出定制化的Linux产品。
  • 示意图:
    image
  • 代码实现:
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char **parts;
    int size;
    int capacity;
} Product1;

void Product1_Init(Product1 *product) {
    product->parts = NULL;
    product->size = 0;
    product->capacity = 0;
}

void Product1_AddPart(Product1 *product, const char *part) {
    if (product->size >= product->capacity) {
        product->capacity = product->capacity == 0 ? 1 : product->capacity * 2;
        product->parts = realloc(product->parts, product->capacity * sizeof(char *));
    }
    product->parts[product->size++] = strdup(part);
}

void Product1_ListParts(Product1 *product) {
    printf("Product parts: ");
    for (int i = 0; i < product->size; i++) {
        printf("%s", product->parts[i]);
        if (i < product->size - 1) {
            printf(", ");
        }
    }
    printf("\n\n");
}

void Product1_Clear(Product1 *product) {
    for (int i = 0; i < product->size; i++) {
        free(product->parts[i]);
    }
    free(product->parts);
    product->parts = NULL;
    product->size = 0;
    product->capacity = 0;
}

typedef struct Builder Builder;

struct Builder {
    void (*ProducePartA)(Builder *);
    void (*ProducePartB)(Builder *);
    void (*ProducePartC)(Builder *);
    Product1 *(*GetProduct)(Builder *);
    Product1 *product;
};

void ConcreteBuilder1_ProducePartA(Builder *builder) {
    Product1_AddPart(builder->product, "PartA1");
}

void ConcreteBuilder1_ProducePartB(Builder *builder) {
    Product1_AddPart(builder->product, "PartB1");
}

void ConcreteBuilder1_ProducePartC(Builder *builder) {
    Product1_AddPart(builder->product, "PartC1");
}

Product1 *ConcreteBuilder1_GetProduct(Builder *builder) {
    Product1 *result = builder->product;
    builder->product = malloc(sizeof(Product1));
    Product1_Init(builder->product);
    return result;
}

Builder *ConcreteBuilder1_Create() {
    Builder *builder = malloc(sizeof(Builder));
    builder->product = malloc(sizeof(Product1));
    Product1_Init(builder->product);
    builder->ProducePartA = ConcreteBuilder1_ProducePartA;
    builder->ProducePartB = ConcreteBuilder1_ProducePartB;
    builder->ProducePartC = ConcreteBuilder1_ProducePartC;
    builder->GetProduct = ConcreteBuilder1_GetProduct;
    return builder;
}

void Builder_Destroy(Builder *builder) {
    Product1_Clear(builder->product);
    free(builder->product);
    free(builder);
}

typedef struct {
    Builder *builder;
} Director;

void Director_SetBuilder(Director *director, Builder *builder) {
    director->builder = builder;
}

void Director_BuildMinimalViableProduct(Director *director) {
    director->builder->ProducePartA(director->builder);
}

void Director_BuildFullFeaturedProduct(Director *director) {
    director->builder->ProducePartA(director->builder);
    director->builder->ProducePartB(director->builder);
    director->builder->ProducePartC(director->builder);
}

void ClientCode(Director *director) {
    Builder *builder = ConcreteBuilder1_Create();
    Director_SetBuilder(director, builder);
    printf("Standard basic product:\n");
    Director_BuildMinimalViableProduct(director);

    Product1 *p = builder->GetProduct(builder);
    Product1_ListParts(p);
    Product1_Clear(p);
    free(p);

    printf("Standard full featured product:\n");
    Director_BuildFullFeaturedProduct(director);

    p = builder->GetProduct(builder);
    Product1_ListParts(p);
    Product1_Clear(p);
    free(p);

    printf("Custom product:\n");
    builder->ProducePartA(builder);
    builder->ProducePartC(builder);
    p = builder->GetProduct(builder);
    Product1_ListParts(p);
    Product1_Clear(p);
    free(p);

    Builder_Destroy(builder);
}

int main() {
    Director director = {NULL};
    ClientCode(&director);
    return 0;
}

c++
/**
 * It makes sense to use the Builder pattern only when your products are quite
 * complex and require extensive configuration.
 *
 * Unlike in other creational patterns, different concrete builders can produce
 * unrelated products. In other words, results of various builders may not
 * always follow the same interface.
 */

class Product1{
    public:
    std::vector<std::string> parts_;
    void ListParts()const{
        std::cout << "Product parts: ";
        for (size_t i=0;i<parts_.size();i++){
            if(parts_[i]== parts_.back()){
                std::cout << parts_[i];
            }else{
                std::cout << parts_[i] << ", ";
            }
        }
        std::cout << "\n\n"; 
    }
};


/**
 * The Builder interface specifies methods for creating the different parts of
 * the Product objects.
 */
class Builder{
    public:
    virtual ~Builder(){}
    virtual void ProducePartA() const =0;
    virtual void ProducePartB() const =0;
    virtual void ProducePartC() const =0;
};
/**
 * The Concrete Builder classes follow the Builder interface and provide
 * specific implementations of the building steps. Your program may have several
 * variations of Builders, implemented differently.
 */
class ConcreteBuilder1 : public Builder{
    private:

    Product1* product;

    /**
     * A fresh builder instance should contain a blank product object, which is
     * used in further assembly.
     */
    public:

    ConcreteBuilder1(){
        this->Reset();
    }

    ~ConcreteBuilder1(){
        delete product;
    }

    void Reset(){
        this->product= new Product1();
    }
    /**
     * All production steps work with the same product instance.
     */

    void ProducePartA()const override{
        this->product->parts_.push_back("PartA1");
    }

    void ProducePartB()const override{
        this->product->parts_.push_back("PartB1");
    }

    void ProducePartC()const override{
        this->product->parts_.push_back("PartC1");
    }

    /**
     * Concrete Builders are supposed to provide their own methods for
     * retrieving results. That's because various types of builders may create
     * entirely different products that don't follow the same interface.
     * Therefore, such methods cannot be declared in the base Builder interface
     * (at least in a statically typed programming language). Note that PHP is a
     * dynamically typed language and this method CAN be in the base interface.
     * However, we won't declare it there for the sake of clarity.
     *
     * Usually, after returning the end result to the client, a builder instance
     * is expected to be ready to start producing another product. That's why
     * it's a usual practice to call the reset method at the end of the
     * `getProduct` method body. However, this behavior is not mandatory, and
     * you can make your builders wait for an explicit reset call from the
     * client code before disposing of the previous result.
     */

    /**
     * Please be careful here with the memory ownership. Once you call
     * GetProduct the user of this function is responsable to release this
     * memory. Here could be a better option to use smart pointers to avoid
     * memory leaks
     */

    Product1* GetProduct() {
        Product1* result= this->product;
        this->Reset();
        return result;
    }
};

/**
 * The Director is only responsible for executing the building steps in a
 * particular sequence. It is helpful when producing products according to a
 * specific order or configuration. Strictly speaking, the Director class is
 * optional, since the client can control builders directly.
 */
class Director{
    /**
     * @var Builder
     */
    private:
    Builder* builder;
    /**
     * The Director works with any builder instance that the client code passes
     * to it. This way, the client code may alter the final type of the newly
     * assembled product.
     */

    public:

    void set_builder(Builder* builder){
        this->builder=builder;
    }

    /**
     * The Director can construct several product variations using the same
     * building steps.
     */

    void BuildMinimalViableProduct(){
        this->builder->ProducePartA();
    }
    
    void BuildFullFeaturedProduct(){
        this->builder->ProducePartA();
        this->builder->ProducePartB();
        this->builder->ProducePartC();
    }
};
/**
 * The client code creates a builder object, passes it to the director and then
 * initiates the construction process. The end result is retrieved from the
 * builder object.
 */
/**
 * I used raw pointers for simplicity however you may prefer to use smart
 * pointers here
 */
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;    
}

原型模式

  • 概念: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

  • 规则: 本质是在对象中增加相应的克隆方法,直接进行变量成员的复制

  • 实现细节: 克隆模式的核心是将克隆操作封装在实际对象中,由实际对象实现。而原型只包含克隆方法的接口

  • 应用场景: 重新创建新对象成本大/初始化需要消耗大量资源/需要对原型备份。Linux中的COW机制即是原型模式的体现,其体现在进程的创建等一系列过程中/同时,原型注册表实现经典实现是GUI的控件功能

  • 示意图:
    基本实现:
    image
    原型注册表实现:
    image

  • 代码实现:

    c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    typedef struct person {
    	//define data
    	char name[32];
    	int age;
    	char sex;
    	//define clone function point
    	struct person* (*clone)(void *obj);
    	//define set function point
    	void (*set)(void *obj, const char *str, int age, char sex);
    	//define show function point
    	void (*show)(void *obj);
    } person_t;
    
    static void person_set(void *obj, const char *str, int age, char sex)
    {
    	if (!obj || !str)
    		return;
    
    	person_t *p = (person_t *)obj;
    	strcpy(p->name, str);
    	p->age = age;
    	p->sex = sex;
    }
    
    static void person_show(void *obj)
    {
    	person_t *p = (person_t *)obj;
    	printf("name: %s, age: %d, sex: %c\n", p->name, p->age, p->sex);
    }
    
    static person_t* person_clone(void *obj)
    {
    	person_t *pobj = (person_t *)malloc(sizeof(person_t));
    	person_t *p = (person_t *)obj;
    	if (!pobj)
    		return NULL;
    
    	pobj->clone = person_clone;
    	pobj->set = person_set;
    	pobj->show = person_show;
    	strcpy(pobj->name, p->name);
    	pobj->age = p->age;
    	pobj->sex = p->sex;
    
    	return pobj;
    }
    
    person_t* constructor_person(void)
    {
    	person_t* p = (person_t *)malloc(sizeof(person_t));
    
    	p->clone = person_clone;
    	p->set = person_set;
    	p->show = person_show;
    
    	return p;
    }
    
    int main(void)
    {
    	//constructor person 注册函数
    	person_t *p = constructor_person();
    	printf("constructor person:\n");
    	p->set(p, "lilei", 14, 'm');
    	p->show(p);
    
    	person_t *p1 = p->clone(p); //直接克隆
    	printf("clone person:\n");
    	p1->show(p1);
    
    	printf("set person:\n"); //设置
    	p1->set(p1, "lucy", 15, 'w');
    	p1->show(p1);
    
    	free(p);
    	free(p1);
    
    	return 0;
    }
    
    c++
    using std::string;
    
    // Prototype Design Pattern
    //
    // Intent: Lets you copy existing objects without making your code dependent on
    // their classes.
    
    enum Type {
      PROTOTYPE_1 = 0,
      PROTOTYPE_2
    };
    
    /**
     * The example class that has cloning ability. We'll see how the values of field
     * with different types will be cloned.
     */
    
    class Prototype {
     protected:
      string prototype_name_;
      float prototype_field_;
    
     public:
      Prototype() {}
      Prototype(string prototype_name)
    	  : prototype_name_(prototype_name) {
      }
      virtual ~Prototype() {}
      virtual Prototype *Clone() const = 0;
      virtual void Method(float prototype_field) {
    	this->prototype_field_ = prototype_field;
    	std::cout << "Call Method from " << prototype_name_ << " with field : " << prototype_field << std::endl;
      }
    };
    
    /**
     * ConcretePrototype1 is a Sub-Class of Prototype and implement the Clone Method
     * In this example all data members of Prototype Class are in the Stack. If you
     * have pointers in your properties for ex: String* name_ ,you will need to
     * implement the Copy-Constructor to make sure you have a deep copy from the
     * clone method
     */
    
    class ConcretePrototype1 : public Prototype {
     private:
      float concrete_prototype_field1_;
    
     public:
      ConcretePrototype1(string prototype_name, float concrete_prototype_field)
    	  : Prototype(prototype_name), concrete_prototype_field1_(concrete_prototype_field) {
      }
    
      /**
       * Notice that Clone method return a Pointer to a new ConcretePrototype1
       * replica. so, the client (who call the clone method) has the responsability
       * to free that memory. If you have smart pointer knowledge you may prefer to
       * use unique_pointer here.
       */
      Prototype *Clone() const override {
    	return new ConcretePrototype1(*this);
      }
    };
    
    class ConcretePrototype2 : public Prototype {
     private:
      float concrete_prototype_field2_;
    
     public:
      ConcretePrototype2(string prototype_name, float concrete_prototype_field)
    	  : Prototype(prototype_name), concrete_prototype_field2_(concrete_prototype_field) {
      }
      Prototype *Clone() const override {
    	return new ConcretePrototype2(*this);
      }
    };
    
    /**
     * In PrototypeFactory you have two concrete prototypes, one for each concrete
     * prototype class, so each time you want to create a bullet , you can use the
     * existing ones and clone those.
     */
    
    class PrototypeFactory {
     private:
      std::unordered_map<Type, Prototype *, std::hash<int>> prototypes_;
    
     public:
      PrototypeFactory() {
    	prototypes_[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f);
    	prototypes_[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f);
      }
    
      /**
       * Be carefull of free all memory allocated. Again, if you have smart pointers
       * knowelege will be better to use it here.
       */
    
      ~PrototypeFactory() {
    	delete prototypes_[Type::PROTOTYPE_1];
    	delete prototypes_[Type::PROTOTYPE_2];
      }
    
      /**
       * Notice here that you just need to specify the type of the prototype you
       * want and the method will create from the object with this type.
       */
      Prototype *CreatePrototype(Type type) {
    	return prototypes_[type]->Clone();
      }
    };
    
    void Client(PrototypeFactory &prototype_factory) {
      std::cout << "Let's create a Prototype 1\n";
    
      Prototype *prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_1);
      prototype->Method(90);
      delete prototype;
    
      std::cout << "\n";
    
      std::cout << "Let's create a Prototype 2 \n";
    
      prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_2);
      prototype->Method(10);
    
      delete prototype;
    }
    
    int main() {
      PrototypeFactory *prototype_factory = new PrototypeFactory();
      Client(*prototype_factory);
      delete prototype_factory;
    
      return 0;
    }
    
    

总结

  • 特点: 创建型模式的核心是如何创建对象,核心思想是将创建的对象和使用分离,使其能够相对独立的变换(开闭原则)。
  • 单例 保证一个类只有一个实例,并提供访问实例的全局节点;
  • 工厂方法: 父类中提供创建对象的接口,从而允许子类决定实例化对象的类型;
  • 抽象工厂: 使其能够创建一系列相关对象,而无需指定具体类;
  • 生成器:分步骤创建复杂对象,可以使用相同的代码生成不同类型和形式的对象;
  • 原型: 提供能够复制已有对象而无需使代码依赖其所属类的技巧。

注意: 目前给出的c语言代码是不完善的,后续会进行进一步校准。

参考文献

廖雪峰的官方网站: https://www.liaoxuefeng.com/wiki/1252599548343744/1264742167474528
c语言和设计模式:https://blog.csdn.net/feixiaoxing/category_951264.html
卡码网设计模式精讲:https://github.com/youngyangyang04/kama-DesignPattern
设计模式:https://www.zhihu.com/column/c_1605852722795917312
设计模式:https://www.zhihu.com/people/infinity-65-77/posts
深入设计模式:https://refactoringguru.cn/design-patterns/builder/cpp/example

posted @ 2024-04-29 10:15  David_Dong  阅读(3)  评论(0编辑  收藏  举报