• 工厂与观察者模式


    工厂模式介绍

    通过一个加工厂,在这个工厂中添加对应材料,我们就可以得到想要的东西,在程序设计中,这种模式就叫做工厂模式,工厂生成出的产品就是某个类的实例,也就是对象。

    关于工厂模式一共有三种,分别是:简单工厂模式、工厂模式、抽象工厂模式。

    简单工厂模式

    比如说你要生产一些物品,生产的方法都是一样的只是原材料不同。你可以设计一个基类,提供生产方法。然后将要生产的对象材料加入到生产类中即可。后面可以再定义一个对象工厂类,用来创建对应材料。

    创建一个新的类, 可以将这个类称之为工厂类。对于简单工厂模式来说,需要的工厂类只有一个。工厂类中添加一个公共的成员函数,通过这个函数来创建我们需要的对象,通过这个对象调用工厂函数,这样就可以生产出一个指定类型的实例对象了。这里可以使用c++中的多态来完成。

    例如:先定义一个基类,将其方法定义为虚函数。

    1. class Product
    2. {
    3. public:
    4. Product()
    5. {
    6. ;
    7. }
    8. virtual void produce()
    9. {
    10. cout << "进行生产" << endl;
    11. }
    12. virtual ~Product()
    13. {
    14. cout << "资源释放" << endl;
    15. }
    16. };

    定义要实例化的对象

    1. class Milk :public Product
    2. {
    3. public:
    4. void produce()
    5. {
    6. cout << "生产了牛奶" << endl;
    7. }
    8. ~Milk()
    9. {
    10. cout << "delete Milk" << endl;
    11. }
    12. };
    13. class Apple :public Product
    14. {
    15. public:
    16. void product()
    17. {
    18. cout << "生产了apple" << endl;
    19. }
    20. ~Apple()
    21. {
    22. cout << "delete apple" << endl;
    23. }
    24. };

    定义物品工厂类,用来生产对应材料

    1. enum class Type :char { milk,apple };
    2. class Factory
    3. {
    4. public:
    5. Product* p = nullptr;
    6. Product* create(Type T)
    7. {
    8. switch (T)
    9. {
    10. case Type::milk:
    11. p = new Milk;
    12. break;
    13. case Type::apple:
    14. p = new Apple;
    15. break;
    16. default:
    17. break;
    18. }
    19. return p;
    20. }
    21. };
    1. int main()
    2. {
    3. Factory* f = new Factory;
    4. Product* p = f->create(Type::milk);//需要生产材料,就对其参数进行修改
    5. p->produce();
    6. delete p;
    7. return 0;
    8. }

    caf69a45a766483da2fc2a1fe83f8b3c.png

     工厂类模式

    如果要可以生成更多种类的物品,需要添加更多的物品对象,同时还要在工厂函数的switch语句中添加更多的case,很明显这违背了封闭原则。

    简单工厂模式是只有一个工厂类,而工厂模式是有很多的工厂类。

     

    1. 一个基类,包含一个虚工厂函数,用于实现多态。
    2. 多个子类,重写父类的工厂函数。每个子工厂类负责生产某种物品,这相当于再次解耦,如果要生产新物品,那么只需要添加对应的工厂类,无需修改原有的代码。

    代码:

    1. class Product
    2. {
    3. public:
    4. virtual void produce()
    5. {
    6. cout << "进行生产" << endl;
    7. }
    8. virtual ~Product()
    9. {
    10. cout << "资源释放" << endl;
    11. }
    12. };
    13. class Milkpro :public Product
    14. {
    15. public:
    16. void produce()
    17. {
    18. cout << "生产了牛奶" << endl;
    19. }
    20. ~Milkpro()
    21. {
    22. cout << "delete Milk" << endl;
    23. }
    24. };
    25. class Applepro :public Product
    26. {
    27. public:
    28. void product()
    29. {
    30. cout << "生产了apple" << endl;
    31. }
    32. ~Applepro()
    33. {
    34. cout << "delete apple" << endl;
    35. }
    36. };
    37. class Factory//并没有在这个类中直接生产材料,而是定义为抽象类
    38. {
    39. public:
    40. virtual Product* creat() = 0;
    41. virtual ~Factory()
    42. {
    43. ;
    44. }
    45. };
    46. class Milk :public Factory
    47. {
    48. public:
    49. Product* creat()
    50. {
    51. return new Milkpro;
    52. }
    53. ~Milk()
    54. {
    55. cout << "delete Milk" << endl;
    56. }
    57. };
    58. class Apple :public Factory
    59. {
    60. public:
    61. Product* creat()
    62. {
    63. return new Applepro;
    64. }
    65. ~Apple()
    66. {
    67. cout << "delete Apple" << endl;
    68. }
    69. };
    70. int main()
    71. {
    72. Factory* f = new Milk;
    73. Product* p= f->creat();
    74. p->produce();
    75. delete p;
    76. return 0;
    77. }

    27ba17f099df42d884bec8c171e88f8f.png

     抽象工厂类

    假如要生产一艘船,该的组成为:

    船体,船的动力系统,船中配备的武器。

    船体的选择:木材 合金

    动力系统的选择:人力驱动,核反应驱动

    武器的选择:枪,自动机关炮

    这样一共就有8种选则。

    船体,因为船体材料的这个属性是可变的,所以还需要给它提供一个抽象类,在这个抽象类的子类中就可以去更换不同的船体材料。

    1. class ShipBody
    2. {
    3. public:
    4. virtual string getShipBody() = 0;
    5. virtual ~ShipBody() {}
    6. };
    7. class WoodBody : public ShipBody
    8. {
    9. public:
    10. string getShipBody() override
    11. {
    12. return string("用<木材>制作轮船船体...");
    13. }
    14. };
    15. class MetalBody : public ShipBody
    16. {
    17. public:
    18. string getShipBody() override
    19. {
    20. return string("用<合金>制作轮船船体...");
    21. }
    22. };

    动力系统与武器也是一样:

    1. // 动力
    2. class Engine
    3. {
    4. public:
    5. virtual string getEngine() = 0;
    6. virtual ~Engine() {}
    7. };
    8. class Human : public Engine
    9. {
    10. public:
    11. string getEngine() override
    12. {
    13. return string("使用<人力驱动>...");
    14. }
    15. };
    16. class Nuclear : public Engine
    17. {
    18. public:
    19. string getEngine() override
    20. {
    21. return string("使用<核能驱动>...");
    22. }
    23. };
    24. // 武器
    25. class Weapon
    26. {
    27. public:
    28. virtual string getWeapon() = 0;
    29. virtual ~Weapon() {}
    30. };
    31. class Gun : public Weapon
    32. {
    33. public:
    34. string getWeapon() override
    35. {
    36. return string("配备的武器是<枪>");
    37. }
    38. };
    39. class Cannon : public Weapon
    40. {
    41. public:
    42. string getWeapon() override
    43. {
    44. return string("配备的武器是<自动机关炮>");
    45. }
    46. };

    一首船需要3个组成部分,这里用3个变量来表示:

    1. class Ship
    2. {
    3. public:
    4. Ship(ShipBody* body, Weapon* weapon, Engine* engine) :
    5. m_body(body), m_weapon(weapon), m_engine(engine)
    6. {
    7. }
    8. string getProperty()
    9. {
    10. // 这也是多态实现,获取对应船组成部分的材料
    11. string info = m_body->getShipBody() + m_weapon->getWeapon() + m_engine->getEngine();
    12. return info;
    13. }
    14. ~Ship()
    15. {
    16. delete m_body;
    17. delete m_engine;
    18. delete m_weapon;
    19. }
    20. private:
    21. ShipBody* m_body = nullptr;
    22. Weapon* m_weapon = nullptr;
    23. Engine* m_engine = nullptr;
    24. };

    工厂类与上面一样,不直接进行提供船部件,而是定义为抽象类,让子类去提供船的部件。

    1. / 工厂类
    2. class AbstractFactory
    3. {
    4. public:
    5. virtual Ship* createShip() = 0;
    6. virtual ~AbstractFactory() {}
    7. };
    8. class BasicFactory : public AbstractFactory//定义木头,枪,人力的船
    9. {
    10. public:
    11. Ship* createShip() override
    12. {
    13. Ship* ship = new Ship(new WoodBody, new Gun, new Human);
    14. cout << "<基础型>战船生产完毕, 可以下水啦..." << endl;
    15. return ship;
    16. }
    17. };

     结果:

    1. int main()
    2. {
    3. AbstractFactory* factroy = new BasicFactory;
    4. Ship* ship = factroy->createShip();
    5. cout << ship->getProperty();
    6. delete ship;
    7. delete factroy;
    8. return 0;
    9. }

    3a2868f99e6b4a99ba5b927555b4d37f.png

    对比:

    • 简单工厂模式不能遵守开放-封闭原则,该工厂类没有设置为抽象类,要在该类中直接添加生产对象。
    • 工厂模式创建的对象  对应的类不需要提供抽象类,需要创建什么对象,直接提供对应的子类
    • 抽象工厂模式创建的对象  对应的类有抽象的基类,创建的对象有多种不同的组合方法。

    观察者模式

    一个简单的例子:交叉路口的红绿灯。过往的车辆就是观察者或则是订阅者,信号灯就是消息的发布者。当车辆到了该路口,车辆就会观测路灯,当路灯为红灯时,车辆即可通行。当车辆远离该路口时,车辆就不需要观察路灯的信号了。

    其他例子:购买的商品被送到菜鸟驿站,会收到驿站发送的提示信息。

    这里以报刊为例,报刊可以发布多种类型的消息给不同的人。

    发布者,需要满足以下的需求:

    • 添加订阅者,将所有的订阅者存储起来
    • 删除订阅者,将其从订阅者列表中删除
    • 将消息发送给订阅者(发通知)

    发布者

    发布者未必是一种类型的,不同的发布者可以发布不同种类的消息。先创建出一个发布者的抽象类。

    class Observer;//订阅者抽象类

    class NewsAgency//发布者抽象类
    {
    public:
        void attach(Observer* ob)
        {
            m_list.push_back(ob);//增加订阅者
        }
        void deatch(Observer* ob)
        {
           m_list.remove(ob);//删除订阅者
        }
        virtual void notify(string msg) = 0;//通知
        virtual ~NewsAgency() {};
    protected:
        list m_list;   // 订阅者列表
    };

    class News_A :public NewsAgency
    {
    public:
        void notify(string msg) override
        {
            cout << "这是NewA新闻报刊" << endl;
            for (auto ch : m_list)
            {
                ch->update(msg);
            }
        }
    };
    class News_B :public NewsAgency
    {
    public:
        void notify(string msg) override
        {
            cout << "这是NewB新闻报刊" << endl;
            for (auto ch : m_list)
            {
                ch->update(msg);
            }
        }
    };

    订阅者

    观察者也未必只是一种对象,给所有的观察者定义一个抽象的基类。

    // 抽象的订阅者类
    class Observer
    {
    public:

      //通过构造函数给观察者类提供一个信息的发布者 
        Observer(string name, NewsAgency* news) :m_name(name), m_news(news) 
        {
            m_news->attach(this);//发布者对象将观察者对象存储了起来,可以收到发布的消息
        }
        void unsubscribe()
        {
            m_news->deatch(this);//订阅者取消订阅
        }
        virtual void update(string msg) = 0;
        virtual ~Observer() {}
    protected:
        string m_name;
        NewsAgency* m_news;
    };

    class Observer_A : public Observer//订阅者A
    {
    public:
        using Observer::Observer;
        void update(string msg) override
        {
            cout << "订阅者A收到新消息: " << msg << endl;
        }
    };

    class Observer_B : public Observer//订阅者B
    {
    public:
        using Observer::Observer;
        void update(string msg) override
        {
            cout << "订阅者B收到新消息: " << msg << endl;
        }
    };

    过程

    1. int main()
    2. {
    3. News_A* New_a = new News_A;
    4. News_B* New_b = new News_B;
    5. Observer_A* obser_a = new Observer_A("observer_A",New_a);
    6. Observer_B* obser_b = new Observer_B("observer_B",New_b);
    7. New_a->notify("明天会下雨哦*************");
    8. New_b->notify("明天广场会进行发布会活动,请大家参加");
    9. return 0;
    10. }

     

     

  • 相关阅读:
    浅析Spring事务实现原理
    Golang 程序启动原理详解
    Kakao账号如何注册使用?如何Kakao多开?外贸必备全面教程
    【构建并发程序】4-原子变量-CAS-ABA问题
    linux(四) -- 常用基本命令
    11-JVM调优实战-1
    JSP知识
    element-ui封装loading,便于在拦截请求或其他场景使用
    卓越:12年开发老兵甩出SpringBoot突击小册,仅7天Github获赞98.5K
    基于JavaWeb+MySQL的学院党费缴费系统
  • 原文地址:https://blog.csdn.net/m0_64397669/article/details/133198204