【设计模式学习笔记】建造者模式和原型模式案例详解(C++实现)

简介: 【设计模式学习笔记】建造者模式和原型模式案例详解(C++实现)

一、建造者模式

1. 什么是建造者模式

Bulider Pattern,建造者模式,也叫做生成器模式,是一种对象创建型模式。建造者模式用于创建具有多个部件的复合对象,并隐藏了复合对象的创建过程,不同的部件建造者(Builder生成器)有不同的建造方法。通过建造者模式实现了对象的构建和对象的表示的分离,也就是说,通过同样的构建过程(建造逻辑)可以创建出不同的表示(使用不同的建造者产生不同的建造方式)。

建造者模式中的4种角色:

  1. 抽象建造者角色Builder:为建造各个组件提供统一的抽象接口;
  2. 具体建造者角色ConcreteBuilder:实现抽象建造者提供的抽象接口,定义各个组件的建造方法,是组件建造的具体实施者;
  3. 指挥者Director:调用具体建造者来建造产品的各个组件,指挥者并不知道产品的具体信息,指挥者只负责规定并保证各个组件的建造过程和建造逻辑(指挥建造的过程,比如先装发动机再装轮子);
  4. 产品角色Product:被建造的复杂对象,包含组合对象的各个部件;

2. 建造者模式的实现

首先我们定义一个汽车产品类,这个汽车包含外壳、发动机、车轮三个部件,并且汽车产品类中应该包含设置各个部件和获取各个部件的方法。汽车产品类是我们最终要建造的目标,是客户的需求。

1. //最终产品类:汽车
2. class CarProduct
3. {
4. public:
5.  void set_shell(string shell) //建造汽车外壳
6.  {
7.    this->shell = shell;
8.  }
9.  void set_engine(string engine) //建造汽车发动机
10.   {
11.     this->engine = engine;
12.   }
13.   void set_whell(string whell) //建造汽车轮子
14.   {
15.     this->whell = whell;
16.   }
17.   //获取属性
18.   string get_shell()
19.   {
20.     return this->shell;
21.   }
22.   string get_engine()
23.   {
24.     return this->engine;
25.   }
26.   string get_whell()
27.   {
28.     return this->whell;
29.   }
30. private:
31.   string shell; //外壳
32.   string engine; //发动机
33.   string whell; //轮子
34. };

定义一个抽象的建造者基类,类中统一了建造部件的接口和返回产品成品的方法。

1. //建造者基类:抽象施工单位
2. class Builder
3. {
4. public:
5.  virtual void builder_shell() = 0; //汽车外壳的建造方式接口
6.  virtual void builder_engine() = 0; //发动机的建造方式
7.  virtual void builder_whell() = 0; //车轮的建造方式
8.  virtual CarProduct* get_car() = 0; //返回建造好的汽车产品
9. };

定义具体建造者类,具体建造者类是产品部件的具体建造者,也就是汽车的生产商,我们定义两个汽车生产商,一个厂家生产卡车,一个厂家生产火车。

1. //具体的建造者:具体施工单位、具体的建造方式
2. class TruckBuilder : public Builder //卡车建造商
3. {
4. private:
5.  CarProduct* m_car;
6. public:
7.  TruckBuilder()
8.  {
9.    this->m_car = new CarProduct; 
10.   }
11.   virtual void builder_shell()
12.   {
13.     this->m_car->set_shell("卡车外壳");
14.   }
15.   virtual void builder_engine()
16.   {
17.     this->m_car->set_engine("卡车发动机");
18.   }
19.   virtual void builder_whell()
20.   {
21.     this->m_car->set_whell("卡车轮子");
22.   }
23.   virtual CarProduct* get_car()
24.   {
25.     return this->m_car;
26.   }
27. };
28. class TrainBuilder : public Builder //火车建造商
29. {
30. private:
31.   CarProduct* m_car;
32. public:
33.   TrainBuilder()
34.   {
35.     this->m_car = new CarProduct;
36.   }
37.   virtual void builder_shell()
38.   {
39.     this->m_car->set_shell("火车外壳");
40.   }
41.   virtual void builder_engine()
42.   {
43.     this->m_car->set_engine("火车发动机");
44.   }
45.   virtual void builder_whell()
46.   {
47.     this->m_car->set_whell("火车轮子");
48.   }
49.   virtual CarProduct* get_car()
50.   {
51.     return this->m_car;
52.   }
53. };

最后,应该定义一个指挥者,指挥者是汽车的设计师,它负责规划建造汽车的逻辑步骤,指挥汽车厂家(具体建造者)干活,而具体的工作有汽车厂家去干,所以指挥者不关心汽车的具体细节,只负责设计建造汽车各个部件的逻辑关系,比如先制造汽车外壳,然后安装发动机,最后安装车轮。

1. //指挥者:设计师,负责设计建造逻辑
2. class Director
3. {
4. public:
5.  Director(Builder* builder)
6.  {
7.    this->m_builder = builder;
8.  }
9.  //建造逻辑
10.   void builder_logic()
11.   {
12.     //1.先建造车的外壳
13.     this->m_builder->builder_shell();
14.     cout << "先建造车的外壳\t";
15.     //2.再安装发动机
16.     this->m_builder->builder_engine();
17.     cout << "再安装发动机\t";
18.     //3.最后安装车轮
19.     this->m_builder->builder_whell();
20.     cout << "最后安装车轮\n";
21.   }
22. private:
23.   Builder* m_builder;
24. };

最后是根据客户需求去建造汽车,假设客户需要一辆卡车。

1. int main()
2. {
3.  CarProduct* myCar = NULL;
4.  Builder* tempBuilder = NULL;
5.  Director* carDector = NULL;
6. 
7.  //需求:建造一辆卡车
8.  //首先找一个卡车建造商
9.  tempBuilder = new TruckBuilder;
10.   //把建造商交给指挥者(设计师)管理
11.   carDector = new Director(tempBuilder);
12.   //开始建造
13.   carDector->builder_logic();
14.   //获取产品  对象的建造逻辑和产品的表示分离
15.   myCar = tempBuilder->get_car();
16.   cout << "======产品信息======" << endl;
17.   cout << myCar->get_shell() << endl;
18.   cout << myCar->get_engine() << endl;
19.   cout << myCar->get_whell() << endl;
20.   cout << "====================" << endl;
21.   delete myCar;
22.   delete carDector;
23.   delete tempBuilder;
24. }

假如客户提出新需求,需要一辆火车,那么我们直接让指挥者去指挥火车厂商生产即可。

1. //新需求:需要一辆火车
2.  tempBuilder = new TrainBuilder;
3.  carDector = new Director(tempBuilder);
4.  carDector->builder_logic();
5.  myCar = tempBuilder->get_car();
6.  cout << "======产品信息======" << endl;
7.  cout << myCar->get_shell() << endl;
8.  cout << myCar->get_engine() << endl;
9.  cout << myCar->get_whell() << endl;
10.   cout << "====================" << endl;
11.   delete myCar;
12.   delete carDector;
13.   delete tempBuilder;

3. 建造者模式和工厂模式对比

建造者模式和工厂模式的区别是:工厂模式强调的是结果,不考虑对象的建造过程,只关注产生一个客户所需要的结果。比如,客户需要一辆大众汽车,那么就直接使用大众汽车工厂来生产一辆大众汽车,只关注大众汽车这个结果,不关心汽车外壳、发动机、轮子等部件的建造过程。建造者模式强调的是建造过程,要关注每一个部件的建造方式,以及各个部件的建造逻辑,最终组合出需要的对象。

二、原型模式

1. 什么是原型模式

Prototype Pattern,原型模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例,所以称之为Clone,被复制出来的对象具有和原型一摸一样的数据,并且在通过Clone创造另一个一模一样的对象时,不需要知道创造的过程。根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

2. 原型模式的实现

既然原型模式是复制一个一模一样的对象,那么就一定要注意潜在的深拷贝浅拷贝问题。

1. #include <iostream>
2. using namespace std;
3. 
4. #include <String>
5. 
6. class MyString
7. {
8. public:
9.  virtual MyString* Clone() = 0;
10.   virtual void print_str() = 0;
11. };
12. 
13. class Hello : public MyString
14. {
15. private:
16.   int len;
17.   string str;
18. public:
19.   Hello()
20.   {
21.     this->len = 5;
22.     this->str = "Hello";
23.   }
24.   virtual MyString* Clone()
25.   {
26.     Hello* temp = new Hello;
27.     *temp = *this;
28.     return temp;
29.   }
30.   virtual void print_str()
31.   {
32.     cout << "len:" << len << "   str:" << str << endl;
33.   }
34. };
35. 
36. int main()
37. {
38.   MyString* h1 = new Hello;
39.   h1->print_str();
40.   MyString* h2 = h1->Clone();
41.   h2->print_str();
42. 
43.   delete h1;
44.   delete h2;
45. 
46.   system("pause");
47.   return 0;
48. }

三、创建型设计模式总结

顾名思义,创建型设计模式就是处理对象创建过程的设计模式。创建型模式主要是将系统所需要的用到的具体类封装起来,在内部实现这些具体类的创建和结合,并对外隐藏这个过程细节。创建型设计模式主要包括:

  • 单例模式
  • 简单工厂模式
  • 工厂模式
  • 抽象工厂模式
  • 建造者模式
  • 原型模式

其中,简单工厂模式因为不符合开闭原则,它不属于标准的23种设计模式。


相关文章
|
14天前
|
设计模式 存储 缓存
「全网最细 + 实战源码案例」设计模式——享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少大量相似对象的内存消耗。通过分离对象的内部状态(可共享、不变)和外部状态(依赖环境、变化),它有效减少了内存使用。适用于存在大量相似对象且需节省内存的场景。模式优点包括节省内存和提高性能,但会增加系统复杂性。实现时需将对象成员变量拆分为内在和外在状态,并通过工厂类管理享元对象。
147 83
|
10天前
|
设计模式 存储 算法
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
48 14
「全网最细 + 实战源码案例」设计模式——命令模式
|
10天前
|
设计模式 存储 Java
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
47 13
「全网最细 + 实战源码案例」设计模式——责任链模式
|
1月前
|
设计模式 缓存 应用服务中间件
「全网最细 + 实战源码案例」设计模式——外观模式
外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。
140 69
|
12天前
|
设计模式 算法 开发者
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
47 8
「全网最细 + 实战源码案例」设计模式——策略模式
|
12天前
|
设计模式 SQL 算法
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
59 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
|
24天前
|
设计模式
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
86 40
|
18天前
|
设计模式 Java 开发者
「全网最细 + 实战源码案例」设计模式——适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,通过引入适配器类将一个类的接口转换为客户端期望的另一个接口,使原本因接口不兼容而无法协作的类能够协同工作。适配器模式分为类适配器和对象适配器两种,前者通过多重继承实现,后者通过组合方式实现,更常用。该模式适用于遗留系统改造、接口转换和第三方库集成等场景,能提高代码复用性和灵活性,但也可能增加代码复杂性和性能开销。
67 28
|
14天前
|
设计模式 存储 安全
「全网最细 + 实战源码案例」设计模式——组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式对待单个对象和对象集合,简化了复杂结构的处理。组合模式包含三个主要组件:抽象组件(Component)、叶子节点(Leaf)和组合节点(Composite)。通过这种模式,客户端可以统一处理简单元素和复杂元素,而无需关心其内部结构。适用于需要实现树状对象结构或希望以相同方式处理简单和复杂元素的场景。优点包括支持树形结构、透明性和遵循开闭原则;缺点是可能引入不必要的复杂性和过度抽象。
72 22
|
18天前
|
设计模式 缓存 Java
「全网最细 + 实战源码案例」设计模式——代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,通过代理对象控制对目标对象的访问并添加额外功能。它分为静态代理和动态代理,后者包括JDK动态代理和CGLIB动态代理。JDK动态代理基于接口反射生成代理类,而CGLIB通过继承目标类生成子类。代理模式适用于延迟初始化、访问控制、远程服务、日志记录和缓存等场景,优点是职责分离、符合开闭原则和提高安全性,缺点是增加系统复杂性。
69 25