当前位置:   article > 正文

设计模式(一)

设计模式(一)

设计模式原则

  • 单一职责原则
    • 含义:每个类应该只有一个职责,只有一个原因可以引起类的变化
    • 目的:通过将不同职责分离到不同的类中,从而提高代码的可读性和可维护性
  • 开闭原则
    • 含义:类、函数等应该对拓展开放、对修改关闭
    • 目的:通过继承和多态机制,允许系统在不修改现有代码的情况下进行拓展,从而提高系统的稳定性和灵活性
  • 里氏替换原则
    • 含义:子类对象必须能够替换其基类对象,并且不会导致程序的逻辑错误
    • 目的:确保继承关系的正确性,使得子类可以完全替代基类
  • 依赖倒置原则
    • 含义:高层模块不应该依赖其底层模块,两者应该依赖其抽象。抽象不依赖其细节,但是细节应该依赖抽象
    • 目的:通过依赖接口或者抽象类类解耦高层和底层的模块,从而提高系统的可维护性和可拓展性
  • 接口隔离原则
    • 含义:客户端不应该依赖它不需要的接口,应该将大的接口拆分的成小的接口
    • 目的:通过使用多个特定客户端接口,而不是一个通用接口,提高系统的灵活性和可维护性
  • 合成/聚合复用原则
    • 含义:多使用对象的合成而不是继承来达到复用的目的
    • 目的:通过组合或者聚合其他对象类实现新的功能
  • 迪米特原则
    • 含义:一个对象应该对其他对象有最少的了解,减少与其他对象的交互
    • 目的:通过减少对象直接的耦合,提高系统的模块化和可维护性

构建型模式

单例模式

单例模式的主要目的是确保一个类在整个程序中只有一个实例,并提供全局的访问点。

单例模式的特点

  • 唯一实例:单例模式确保一个类只有一个实例存在,避免了不必要的实例化,节省了系统资源。
  • 全局访问点:单例模式提供了一个全局访问点,可以通过这个访问点获取唯一的实例。
  • 控制实例创建:通过单例模式,程序可以更好地控制实例的创建和生命周期。

单例模式的应用场景

  •  需要全局访问的唯一实例:如日志系统、配置管理、线程池、数据库连接等。
  • 节省资源:某些资源消耗较大的对象,如文件系统、数据库连接等,可以通过单例模式避免重复创建,节省资源。
  • 控制实例数量:需要严格控制某个类的实例数量,避免过多的实例对系统性能造成影响。

单例模式的优缺点

  •  优点
    • 节省资源:通过控制实例的创建数量,节省系统资源。
    • 全局访问:提供一个全局访问点,方便获取唯一实例。
    • 实例控制:严格控制实例的创建和生命周期,确保系统的一致性。
  • 缺点

    • 难以扩展:单例模式限制了类的扩展,增加新功能时可能需要修改现有代码。
    • 隐藏依赖:全局访问点可能导致依赖关系隐藏,使代码难以理解和维护。
    • 并发问题:在多线程环境下,需要特别注意线程安全问题,否则可能导致多个实例被创建。

Effective C++提供方法(仅支持C++11以后)

  1. template<typename T>
  2. class Singleton {
  3. private:
  4. Singleton(){}
  5. ~Singleton(){}
  6. public:
  7. Singleton(const Singleton&) = delete;
  8. Singleton& operator = (const Singleton) = delete;
  9. static T& getInstance() {
  10. static Singleton _eton;
  11. return _eton;
  12. }
  13. };

饿汉式

类加载的时候就创建实例,线程安全但是可能会造成资源浪费。(害怕吃不上,提前准备好)

相似方法总结

  • 构造函数私有化,防止外部进行实例
  • 禁止拷贝构造函数和赋值运算运算,防止被复制
  • 互斥锁的设计
  • 静态实例,类外初始化
  • 公共方法中提供全局访问点
  1. class Singleton
  2. {
  3. private:
  4. Singleton() {};
  5. Singleton(const Singleton&) = delete;
  6. Singleton& operator=(const Singleton&) = delete;
  7. static Singleton* instance;
  8. public:
  9. static Singleton* getInstance()
  10. {
  11. return instance;
  12. }
  13. };
  14. //Singleton* instance = nullptr;
  15. Singleton* Singleton::instance = nullptr;

懒汉式

第一次调用的时候,再创建实例,避免资源的浪费,但是可能会造成线程不安全。

  1. class Singleton_lazy
  2. {
  3. private:
  4. Singleton_lazy(){}
  5. Singleton_lazy(const Singleton_lazy&) = delete;
  6. Singleton_lazy& operator = (const Singleton&) = delete;
  7. static Singleton_lazy* instance;
  8. public:
  9. static Singleton_lazy* getInstance()
  10. {
  11. if (instance == nullptr)
  12. {
  13. instance == new Singleton_lazy();
  14. }
  15. return instance;
  16. }
  17. };
  18. Singleton_lazy* Singleton_lazy::instance = nullptr;

 线程安全的懒汉式

使用互斥锁去保证线程安全。

  1. #include<mutex>
  2. class Singleton_lazy_mutex
  3. {
  4. private:
  5. Singleton_lazy_mutex(){}
  6. Singleton_lazy_mutex(const Singleton_lazy_mutex&) = delete;
  7. Singleton_lazy_mutex& operator = (const Singleton_lazy_mutex&) = delete;
  8. static Singleton_lazy_mutex* instance;
  9. static std::mutex mtx;
  10. public:
  11. Singleton_lazy_mutex* getInstance()
  12. {
  13. std::lock_guard<std::mutex> lock(mtx);
  14. if (instance == nullptr)
  15. {
  16. instance = new Singleton_lazy_mutex();
  17. }
  18. return instance;
  19. }
  20. };
  21. Singleton_lazy_mutex* Singleton_lazy_mutex::instance = nullptr;
  22. std::mutex Singleton_lazy_mutex::mtx;

C++11标准实现线程安全

C++11引入线程安全的静态局部变量初始化

  1. class singleton_11
  2. {
  3. private:
  4. singleton_11(){}
  5. singleton_11(const singleton_11&) = delete;
  6. singleton_11& operator=(const singleton_11&) = delete;
  7. public:
  8. static singleton_11& getInstance()
  9. {
  10. static singleton_11 instance;
  11. return instance;
  12. }
  13. };

双重检查锁定

第一次检查的时候不加锁,只有实例为空的时候才可以加锁,减少了加锁的开销。

  1. class singleton_double
  2. {
  3. private:
  4. singleton_double(){}
  5. singleton_double(const singleton_double&) = delete;
  6. singleton_double& operator=(const singleton_double&) = delete;
  7. static singleton_double* instance;
  8. static std::mutex mtx;
  9. public:
  10. singleton_double* getInstance()
  11. {
  12. if (instance == nullptr)
  13. {
  14. std::lock_guard<std::mutex> lock(mtx);
  15. if (instance == nullptr)
  16. {
  17. instance = new singleton_double();
  18. }
  19. }
  20. return instance;
  21. }
  22. };
  23. singleton_double* singleton_double::instance = nullptr;
  24. std::mutex singleton_double::mtx;

工厂模式

简单工厂模式

设计一个汽车工厂,当需要某种类型的汽车时,直接告诉工厂自己的需求即可,不需要关注汽车的各种零部件如何组装,也不需要关注不同的类型的汽车的设计图纸。作为用户只需要问工厂伸手要就行。

简单工厂模式即是让工厂承担构建所有的对象的全部职责。用户想要什么类型的产品,只需让工厂生产出来即可。

工厂模式的弊端

  • 超级类的产生:当生产的要求过多的时候,工厂需要承担的职责就会变多,从而变成超级类。例如市场对汽车的类型需要多样,从而导致工厂需要不断的更改其方法。工厂类此时拥有多个引起修改的原因,违背了单一职责原则。
  • 生产新产品的时候,必须在工厂类中添加新的分支。违反设计模式中的开闭原则,因为的开闭原则下要求增加新功能的时候,只需要增加新的类,而不是修改现在已经拥有的类。
  • 增加程序的复杂性,提高调试和维护成本:如果是一个简单的系统中,直接创建类对象可能比通过工厂类来创建更加的简单明了。

  1. #include <iostream>
  2. #include <string>
  3. // 抽象产品类
  4. class Product {
  5. public:
  6. virtual void use() = 0;
  7. };
  8. // 具体产品类A
  9. class ConcreteProductA : public Product {
  10. public:
  11. void use() override {
  12. std::cout << "Using Product A" << std::endl;
  13. }
  14. };
  15. // 具体产品类B
  16. class ConcreteProductB : public Product {
  17. public:
  18. void use() override {
  19. std::cout << "Using Product B" << std::endl;
  20. }
  21. };
  22. // 工厂类
  23. class SimpleFactory {
  24. public:
  25. static Product* createProduct(const std::string& type) {
  26. if (type == "A") {
  27. return new ConcreteProductA();
  28. } else if (type == "B") {
  29. return new ConcreteProductB();
  30. }
  31. return nullptr;
  32. }
  33. };
  34. // 客户端代码
  35. int main() {
  36. Product* productA = SimpleFactory::createProduct("A");
  37. if (productA) {
  38. productA->use();
  39. delete productA;
  40. }
  41. Product* productB = SimpleFactory::createProduct("B");
  42. if (productB) {
  43. productB->use();
  44. delete productB;
  45. }
  46. return 0;
  47. }

工厂方法模式

工厂方法模式的产生就是为了解决简单工厂模式弊端。工厂方法模式规定每一个产品都有一个专属的工厂,例如越野车有越野车的工厂,轿车有轿车的工厂等。

工厂方法模式解决简单工厂模式的弊端。首先,生产的汽车种类变多的时候,工厂类不会变成超级类,当需要修改某个汽车厂只需要对某个汽车厂进行修改,不需要像之前对总工厂进行修改。从而符合单一职责的设计原则。其次,当生产新的汽车类型的时候,不需要修改现有的工厂,只需要添加新的工厂即可。保持了面向对象的可拓展性,符合开闭原则。

优缺点

  • 优点

    • 遵循开闭原则:可以在不修改现有代码的情况下增加新的产品类。
    • 代码复用:工厂方法将具体产品的实例化逻辑封装在子类中,避免了重复代码。
    • 解耦:将对象的创建与使用分离,减少了类之间的耦合。
    • 单一职责原则:每个具体工厂类只负责一种具体产品的创建,职责单一,代码更清晰。
  • 缺点

    • 增加复杂性:每增加一个产品类,就需要增加一个相应的具体工厂类,增加了系统的复杂性。
    • 类爆炸:可能会引入大量的子类,导致类数量急剧增加,维护起来比较繁琐。
  1. class Product
  2. {
  3. public:
  4. virtual void use() = 0;
  5. virtual ~Product(){}
  6. };
  7. class car1 :public Product
  8. {
  9. public:
  10. void use()override
  11. {
  12. std::cout << "越野车生产方法" << std::endl;
  13. }
  14. };
  15. class car2 :public Product
  16. {
  17. public:
  18. void use() override
  19. {
  20. std::cout << "轿车生产方法" << std::endl;
  21. }
  22. };
  23. class Factory
  24. {
  25. public:
  26. virtual Product* createProduct() = 0;
  27. virtual ~Factory(){}
  28. };
  29. class createCar1 :public Factory
  30. {
  31. public:
  32. Product* createProduct() override
  33. {
  34. return new car1;
  35. }
  36. };
  37. class createCar2 :public Factory
  38. {
  39. public:
  40. Product* createProduct()override
  41. {
  42. return new car2;
  43. }
  44. };
  45. int main()
  46. {
  47. //建造越野车工厂,生产越野车
  48. Factory* factory1 = new createCar1();
  49. Product* product1 = factory1->createProduct();
  50. product1->use();
  51. delete product1;
  52. delete factory1;
  53. //小轿车工厂,生产小轿车
  54. Factory* factory2 = new createCar2();
  55. Product* product2 = factory2->createProduct();
  56. product2->use();
  57. delete product2;
  58. delete factory2;
  59. return 0;
  60. }

抽象工厂模式

抽象工厂可以理解为一个超级工厂,通过该工厂可以创建生产其他各种类型物品的子工厂。这些生成的子工厂可以按照工厂的逻辑提供具体函数实现或者对象。

  1. class Fruit {
  2. public:
  3. Fruit(){}
  4. virtual void show() = 0;
  5. };
  6. class Apple :public Fruit {
  7. public:
  8. Apple(){}
  9. void show()override {
  10. std::cout << "生产苹果" << std::endl;
  11. }
  12. };
  13. class Banana :public Fruit {
  14. public:
  15. Banana(){}
  16. void show()override {
  17. std::cout << "生产香蕉" << std::endl;
  18. }
  19. };
  20. class Animal {
  21. public:
  22. virtual void voice() = 0;
  23. };
  24. class Dog :public Animal {
  25. public:
  26. void voice() override {
  27. std::cout << "呕吼~~~" << std::endl;
  28. }
  29. };
  30. class Lamp :public Animal {
  31. public:
  32. void voice() override {
  33. std::cout << "沸羊羊" << std::endl;
  34. }
  35. };
  36. //将水果工厂和动物工厂进行组合(“超级工厂”)
  37. class Factory {
  38. public:
  39. virtual std::shared_ptr<Fruit> getFruit(const std::string& name) = 0;
  40. virtual std::shared_ptr<Animal>getAnimal(const std::string& name) = 0;
  41. };
  42. //水果分厂
  43. class FruitFactory :public Factory {
  44. public:
  45. std::shared_ptr<Animal> getAnimal(const std::string& name) override {
  46. return std::shared_ptr<Animal>();
  47. }
  48. std::shared_ptr<Fruit> getFruit(const std::string& name) override {
  49. if (name == "苹果") {
  50. return std::make_shared<Apple>();
  51. }
  52. else if (name == "香蕉") {
  53. return std::make_shared<Banana>();
  54. }
  55. return std::shared_ptr<Fruit>();
  56. }
  57. };
  58. //动物分厂
  59. class AnimalFactory :public Factory {
  60. public:
  61. std::shared_ptr<Fruit> getFruit(const std::string& name) override {
  62. return std::shared_ptr<Fruit>();
  63. }
  64. std::shared_ptr<Animal>getAnimal(const std::string& name) override {
  65. if (name == "羊") {
  66. return std::make_shared<Lamp>();
  67. }
  68. else if (name == "狗") {
  69. return std::make_shared<Dog>();
  70. }
  71. return shared_ptr<Animal>();
  72. }
  73. };
  74. //工厂生产者
  75. class FactorProducter {
  76. public:
  77. static std::shared_ptr<Factory>getFacory(const std::string& name) {
  78. if (name == "动物") {
  79. return std::make_shared<AnimalFactory>();
  80. }
  81. else {
  82. return std::make_shared<FruitFactory>();
  83. }
  84. }
  85. };
  86. int main()
  87. {
  88. //利用超级工厂(FactorProducter)创建一个生产水果的工厂(FruitFactory)
  89. std::shared_ptr<Factory> fruit_factory = FactorProducter::getFacory("果子");
  90. //然后水果工厂根据需求生产出苹果和香蕉
  91. std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");
  92. fruit->show();
  93. fruit = fruit_factory->getFruit("香蕉");
  94. fruit->show();
  95. std::shared_ptr<Factory> animal_factory = FactorProducter::getFacory("动物");
  96. std::shared_ptr<Animal> animal = animal_factory->getAnimal("狗");
  97. animal->voice();
  98. return 0;
  99. }

建造者模式

建造者模式,即是用简单的对象一步一步构建成一个复杂对象的模式,将创建复杂对象的类进行分离,从而提供构建复杂对象的方法。

实现核心分析

  • 抽象产品类
  • 具体产品类:从抽象产品类构建的具体产品
  • 抽象Builder类:构建一个产品对象,所需要工具的抽象
  • 具体产品的Builder类:实现抽象接口,构建具体的组件
  • 指挥者Director类:统一组件过程,提供给调用者使用,通过指挥者来构建具体的产品

 

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include<iostream>
  3. #include<memory>
  4. #include<string>
  5. using namespace std;
  6. //抽象电脑类
  7. class Computer {
  8. protected:
  9. string _board;
  10. string _display;
  11. string _os;
  12. public:
  13. using ptr = shared_ptr<Computer>;
  14. Computer(){}
  15. //主板、显示器、系统g
  16. void setBoard(const string& board) { _board = board; }
  17. void setDisplay(const string& display) { _display = display; }
  18. virtual void setOs() = 0;
  19. //转换为字符串
  20. string toString() {
  21. string computer = "Computer:{\n";
  22. computer += "\tboard=" + _board + ",\n";
  23. computer += "\tdisplay=" + _display + "\n";
  24. computer += "\tOs=" + _os + ",\n";
  25. computer += "}\n";
  26. return computer;
  27. }
  28. };
  29. //具体产品
  30. class Lenovo :public Computer {
  31. public:
  32. using ptr = shared_ptr<Lenovo>;
  33. Lenovo(){}
  34. void setOs()override {
  35. _os = "Amd 8090";
  36. }
  37. };
  38. //抽象建造者模式
  39. class Builder {
  40. public:
  41. using ptr = shared_ptr<Builder>;
  42. virtual void buildBoard(const string& board) = 0;
  43. virtual void buildDisplay(const string& display) = 0;
  44. virtual void buildOs() = 0;
  45. virtual Computer::ptr build() = 0;
  46. };
  47. //建造者构建具体产品
  48. class LenoveBuilder :public Builder
  49. {
  50. public:
  51. using ptr = shared_ptr<LenoveBuilder>;
  52. LenoveBuilder():_computer(new Lenovo()){}
  53. void buildBoard(const string& board)override
  54. {
  55. _computer->setBoard(board);
  56. }
  57. void buildDisplay(const string& display)override
  58. {
  59. _computer->setDisplay(display);
  60. }
  61. void buildOs() override
  62. {
  63. _computer->setOs();
  64. }
  65. Computer::ptr build() override
  66. {
  67. return _computer;
  68. }
  69. private:
  70. Computer::ptr _computer;
  71. };
  72. //指挥者
  73. class Director {
  74. private:
  75. Builder::ptr _builder;
  76. public:
  77. Director(Builder* builder) :_builder(builder){}
  78. void construct(const string& board, const string& display) {
  79. _builder->buildBoard(board);
  80. _builder->buildDisplay(display);
  81. _builder->buildOs();
  82. }
  83. };
  84. int main()
  85. {
  86. //老板先找一个联想程序员,然后让该程序员干活(构建一个电脑并打印出来)
  87. Builder* build = new LenoveBuilder();
  88. unique_ptr<Director> pd(new Director(build));
  89. pd->construct("amd", "三星");
  90. Computer::ptr computer = build->build();
  91. cout << computer->toString();
  92. return 0;
  93. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/974967?site
推荐阅读
相关标签
  

闽ICP备14008679号