模式步步演化组合使用示例

本篇模拟随着需求的变化,模型步步演化,做个杀鸡使用牛刀的组合示例。
参考:设计模式之复合模式。
系统:Windows 7 64位
IDE:VS 2012

1、策略
需求:池塘边有一群红头鸭(RedheadDuck)和绿头鸭(MallarDuck),也有观察人员放置的鸭鸣器(DuckCall),还有附近儿童在玩的橡皮鸭(RubberDuck)。我们需要可视化鸭子叫声。
鸭子叫声:呱呱(quack)
鸭鸣器:咵咵(kwak)
橡皮鸭:吱吱(squeak)

既然叫声如此多种,我们就把叫声做成策略。
类图如下。
模式步步演化组合使用示例_第1张图片
图1 策略类图

实现代码如下step_1.h。

#include <memory>
#include <iostream>
#include <string>

namespace STEP_1
{
    class QuackBehavior
    {
    public:
        virtual void quack() = 0;
    };

    class Quack : public QuackBehavior
    {
    public:
        virtual void quack() {std::cout<<"呱呱";}
    };

    class Kwak : public QuackBehavior
    {
    public:
        virtual void quack() {std::cout<<"咵咵";}
    };

    class Squeak : public QuackBehavior
    {
    public:
        virtual void quack() {std::cout<<"吱吱";}
    };

    class Quackable
    {
    public:
        virtual void quack() = 0;
    };

    class Duck : public Quackable
    {
    public:
        Duck()
            : m_QuackBehavior(std::unique_ptr<QuackBehavior>(new Quack))
            , m_sName("鸭子")
        {}

        virtual void quack()
        {
            std::cout<<m_sName<<":";
            if (m_QuackBehavior.get() != nullptr)
            {
                m_QuackBehavior->quack();
            }
            std::cout<<std::endl;
        }

    protected:
        std::unique_ptr<QuackBehavior> m_QuackBehavior;
        std::string m_sName;
    };

    class RedheadDuck : public Duck
    {
    public:
        RedheadDuck()
        {
            m_QuackBehavior = std::unique_ptr<QuackBehavior>(new Quack);
            m_sName = "红头鸭";
        }
    };

    class MallarDuck : public Duck
    {
    public:
        MallarDuck()
        {
            m_QuackBehavior = std::unique_ptr<QuackBehavior>(new Quack);
            m_sName = "绿头鸭";
        }
    };

    class RubberDuck : public Duck
    {
    public:
        RubberDuck()
        {
            m_QuackBehavior = std::unique_ptr<QuackBehavior>(new Squeak);
            m_sName = "橡皮鸭";
        }
    };

    class DuckCall : public Duck
    {
    public:
        DuckCall()
        {
            m_QuackBehavior = std::unique_ptr<QuackBehavior>(new Kwak);
            m_sName = "鸭鸣器";
        }
    };

    void Simulate(Quackable* duck)
    {
        if (duck != nullptr)
        {
            duck->quack();
        }
    }

    void Test()
    {
        std::unique_ptr<Quackable> mallardDuck = std::unique_ptr<Quackable>(new MallarDuck);
        std::unique_ptr<Quackable> redheadDuck = std::unique_ptr<Quackable>(new RedheadDuck);
        std::unique_ptr<Quackable> duckCall = std::unique_ptr<Quackable>(new DuckCall);
        std::unique_ptr<Quackable> rubberDuck = std::unique_ptr<Quackable>(new RubberDuck);

        Simulate(mallardDuck.get());
        Simulate(redheadDuck.get());
        Simulate(duckCall.get());
        Simulate(rubberDuck.get());
    }
}

运行结果:
绿头鸭:呱呱
红头鸭:呱呱
鸭鸣器:咵咵
橡皮鸭:吱吱

2、适配器
需求:池塘边又来了一群鹅,可视化鹅(Goose)的叫声。
鹅的叫声:嘎嘎(honk)

采用鹅的适配器将其适配成鸭子,以同样的方式观察其鸣叫。
模式步步演化组合使用示例_第2张图片
图2 适配器类图
实现代码如下step_2.h。

#include "step_1.h"

namespace STEP_2
{
    class Goose
    {
    public:
        void honk() {std::cout<<"鹅:嘎嘎"<<std::endl;}
    };

    class GooseAdapter : public STEP_1::Quackable
    {
    public:
        GooseAdapter(Goose* pGoose)
            : m_pGoose(pGoose)
        {}

        virtual void quack()
        {
            if (m_pGoose != nullptr)
            {
                m_pGoose->honk();
            }
        }

    private:
        Goose* m_pGoose;
    };

    void Test()
    {
        STEP_1::Test();

        auto gooseReal = std::unique_ptr<Goose>(new Goose());
        auto gooseDuck = std::unique_ptr<STEP_1::Quackable>(new GooseAdapter(gooseReal.get()));
        STEP_1::Simulate(gooseDuck.get());
    }
}

运行结果:
绿头鸭:呱呱
红头鸭:呱呱
鸭鸣器:咵咵
橡皮鸭:吱吱
鹅:嘎嘎

3、装饰者
需求:对所有叫声进行计数统计。
这时采用装饰者,对已有功能添加装饰。

图3 装饰者类图

实现代码如下step_3.h。

#pragma once
#include "step_2.h"

namespace STEP_3
{
    class QuackCounter : public STEP_1::Quackable
    {
    public:
        QuackCounter(STEP_1::Quackable* duck)
            : m_pDuck(duck)
        {}

        virtual void quack()
        {
            if (m_pDuck != nullptr)
            {
                m_pDuck->quack();
                ++s_NumberOfQuacks;
            }
        }

        static int GetQuacks() {return s_NumberOfQuacks;}

    private:
        STEP_1::Quackable* m_pDuck;
        static int s_NumberOfQuacks;
    };

    int QuackCounter::s_NumberOfQuacks = 0;

    void Test()
    {
        auto mallardReal = std::unique_ptr<STEP_1::Quackable>(new STEP_1::MallarDuck);
        auto mallardDuck = std::unique_ptr<STEP_1::Quackable>(new QuackCounter(mallardReal.get()));

        auto redheadReal = std::unique_ptr<STEP_1::Quackable>(new STEP_1::RedheadDuck);
        auto redheadDuck = std::unique_ptr<STEP_1::Quackable>(new QuackCounter(redheadReal.get()));

        auto duckReal = std::unique_ptr<STEP_1::Quackable>(new STEP_1::DuckCall);
        auto duckCall = std::unique_ptr<STEP_1::Quackable>(new QuackCounter(duckReal.get()));

        auto rubberReal = std::unique_ptr<STEP_1::Quackable>(new STEP_1::RubberDuck);
        auto rubberDuck = std::unique_ptr<STEP_1::Quackable>(new QuackCounter(rubberReal.get()));

        auto gooseReal = std::unique_ptr<STEP_2::Goose>(new STEP_2::Goose());
        auto gooseAdapter = std::unique_ptr<STEP_1::Quackable>(new STEP_2::GooseAdapter(gooseReal.get()));
        auto gooseDuck = std::unique_ptr<STEP_1::Quackable>(new QuackCounter(gooseAdapter.get()));

        STEP_1::Simulate(mallardDuck.get());
        STEP_1::Simulate(redheadDuck.get());
        STEP_1::Simulate(duckCall.get());
        STEP_1::Simulate(rubberDuck.get());
        STEP_1::Simulate(gooseDuck.get());

        int nQuacks = QuackCounter::GetQuacks();
        std::cout<<"鸣叫声共:"<<nQuacks<<"次"<<std::endl;
    }
}

运行结果如下。
绿头鸭:呱呱
红头鸭:呱呱
鸭鸣器:咵咵
橡皮鸭:吱吱
鹅:嘎嘎
鸣叫声共:5次
4、抽象工厂
观察上述代码,我们发现鸭子创建暴露了太多细节出来,需要计数的时候有可能会忘记进行装饰者包装。
针对这个问题,采用抽象工厂将鸭子创建封装起来。
模式步步演化组合使用示例_第3张图片
图4 抽象工厂类图
实现代码如下step_4.h。

#pragma once
#include "step_3.h"

namespace STEP_4
{
    //改造下QuackCounter,支持智能指针
    class QuackCounter : public STEP_1::Quackable
    {
    public:
        QuackCounter(std::shared_ptr<STEP_1::Quackable> duck)
            : m_pDuck(duck)
        {}

        virtual void quack()
        {
            if (m_pDuck.get() != nullptr)
            {
                m_pDuck->quack();
                ++s_NumberOfQuacks;
            }
        }

        static int GetQuacks() {return s_NumberOfQuacks;}

    private:
        std::shared_ptr<STEP_1::Quackable> m_pDuck;
        static int s_NumberOfQuacks;
    };

    int QuackCounter::s_NumberOfQuacks = 0;

    //鸭子工厂
    class IAbstractFactory
    {
    public:
        IAbstractFactory() {}
        virtual ~IAbstractFactory() {}

        virtual std::shared_ptr<STEP_1::Quackable> CreateMallarDuck() = 0;
        virtual std::shared_ptr<STEP_1::Quackable> CreateRedheadDuck() = 0;
        virtual std::shared_ptr<STEP_1::Quackable> CreateDuckCall() = 0;
        virtual std::shared_ptr<STEP_1::Quackable> CreateRubberDuck() = 0;
    };

    class DuckFactory : IAbstractFactory
    {
    public:
        virtual std::shared_ptr<STEP_1::Quackable> CreateMallarDuck()
        {
            return std::shared_ptr<STEP_1::Quackable>(new STEP_1::MallarDuck);
        }

        virtual std::shared_ptr<STEP_1::Quackable> CreateRedheadDuck()
        {
            return std::shared_ptr<STEP_1::Quackable>(new STEP_1::RedheadDuck);
        }

        virtual std::shared_ptr<STEP_1::Quackable> CreateDuckCall()
        {
            return std::shared_ptr<STEP_1::Quackable>(new STEP_1::DuckCall);
        }

        virtual std::shared_ptr<STEP_1::Quackable> CreateRubberDuck()
        {
            return std::shared_ptr<STEP_1::Quackable>(new STEP_1::RubberDuck);
        }
    };

    class CountingDuckFactory : IAbstractFactory
    {
    public:
        virtual std::shared_ptr<STEP_1::Quackable> CreateMallarDuck()
        {
            auto mallardReal = std::shared_ptr<STEP_1::Quackable>(new STEP_1::MallarDuck);
            return std::shared_ptr<STEP_1::Quackable>(new QuackCounter(mallardReal));
        }

        virtual std::shared_ptr<STEP_1::Quackable> CreateRedheadDuck()
        {
            auto redheadReal = std::shared_ptr<STEP_1::Quackable>(new STEP_1::RedheadDuck);
            return std::shared_ptr<STEP_1::Quackable>(new QuackCounter(redheadReal));
        }

        virtual std::shared_ptr<STEP_1::Quackable> CreateDuckCall()
        {
            auto duckReal = std::shared_ptr<STEP_1::Quackable>(new STEP_1::DuckCall);
            return std::shared_ptr<STEP_1::Quackable>(new QuackCounter(duckReal));
        }

        virtual std::shared_ptr<STEP_1::Quackable> CreateRubberDuck()
        {
            auto rubberReal = std::shared_ptr<STEP_1::Quackable>(new STEP_1::RubberDuck);
            return std::shared_ptr<STEP_1::Quackable>(new QuackCounter(rubberReal));
        }
    };

    void Test()
    {
        std::unique_ptr<IAbstractFactory> m_pDuckFactory = std::unique_ptr<IAbstractFactory>(new CountingDuckFactory);

        auto mallardDuck = m_pDuckFactory->CreateMallarDuck();
        auto redheadDuck = m_pDuckFactory->CreateRedheadDuck();
        auto duckCall = m_pDuckFactory->CreateDuckCall();
        auto rubberDuck = m_pDuckFactory->CreateRubberDuck();

        STEP_1::Simulate(mallardDuck.get());
        STEP_1::Simulate(redheadDuck.get());
        STEP_1::Simulate(duckCall.get());
        STEP_1::Simulate(rubberDuck.get());

        int nQuacks = QuackCounter::GetQuacks();
        std::cout<<"鸣叫声共:"<<nQuacks<<"次"<<std::endl;
    }
}

运行结果如下。
绿头鸭:呱呱
红头鸭:呱呱
鸭鸣器:咵咵
橡皮鸭:吱吱
鸣叫声共:4次
5、组合与迭代器
我们需要管理的不止是单个鸭子,而是一群鸭子,此时采用组合来化零为整,采用迭代器来隐藏实现细节将遍历算法固定。
模式步步演化组合使用示例_第4张图片
图5 组合迭代器类图
实现代码如下step_5.h。

#pragma once
#include <list>
#include "step_4.h"

namespace STEP_5
{
    class DuckIterator
    {
    public:
        DuckIterator() {}
        virtual ~DuckIterator() {}

        virtual bool HasNext() = 0;
        virtual std::shared_ptr<STEP_1::Quackable> Next() = 0;
    };

    class DuckListIterator
    {
    public:
        DuckListIterator(const std::list<std::shared_ptr<STEP_1::Quackable>>& inList)
            : quackers(inList)
        {
            mCurIter = quackers.begin();
        }

        virtual bool HasNext()
        {
            return (mCurIter != quackers.end());
        }

        virtual std::shared_ptr<STEP_1::Quackable> Next()
        {
            const std::shared_ptr<STEP_1::Quackable>& rtnItem = (*mCurIter);
            ++mCurIter;
            return rtnItem;
        }

    private:
        std::list<std::shared_ptr<STEP_1::Quackable>> quackers;
        std::list<std::shared_ptr<STEP_1::Quackable>>::iterator mCurIter;
    };

    class DuckFlock : public STEP_1::Quackable
    {
    public:
        //interfacoe of Quackable
        virtual void quack()
        {
            DuckListIterator duckIterator(quackers);
            while (duckIterator.HasNext())
            {
                const std::shared_ptr<STEP_1::Quackable>& pItem = duckIterator.Next();
                pItem->quack();
            }
        }

        void Add(const std::shared_ptr<STEP_1::Quackable>& item)
        {
            quackers.push_back(item);
        }

    private:
        std::list<std::shared_ptr<STEP_1::Quackable>> quackers;
    };

    void Test()
    {
        std::unique_ptr<STEP_4::IAbstractFactory> m_pDuckFactory = std::unique_ptr<STEP_4::IAbstractFactory>(new STEP_4::CountingDuckFactory);

        auto mallardDuck = m_pDuckFactory->CreateMallarDuck();
        auto redheadDuck = m_pDuckFactory->CreateRedheadDuck();
        auto duckCall = m_pDuckFactory->CreateDuckCall();
        auto rubberDuck = m_pDuckFactory->CreateRubberDuck();
        auto gooseReal = std::shared_ptr<STEP_2::Goose>(new STEP_2::Goose());
        auto gooseAdapter = std::shared_ptr<STEP_1::Quackable>(new STEP_2::GooseAdapter(gooseReal.get()));

        std::shared_ptr<DuckFlock> flockOfDucks = std::shared_ptr<DuckFlock>(new DuckFlock);
        flockOfDucks->Add(mallardDuck);
        flockOfDucks->Add(redheadDuck);
        flockOfDucks->Add(duckCall);
        flockOfDucks->Add(rubberDuck);
        flockOfDucks->Add(gooseAdapter);

        //添加一组绿头鸭
        std::shared_ptr<DuckFlock> flockOfMallards = std::shared_ptr<DuckFlock>(new DuckFlock);
        for (int i = 0; i < 4; i++)
        {
            flockOfMallards->Add(m_pDuckFactory->CreateMallarDuck());
        }
        flockOfDucks->Add(flockOfMallards);

        //测试一整群
        std::cout<<"--------------------------"<<std::endl;
        STEP_1::Simulate(flockOfDucks.get());
        std::cout<<"--------------------------"<<std::endl;
        std::cout<<"--------------------------"<<std::endl;
        //测试绿头鸭
        STEP_1::Simulate(flockOfMallards.get());
        std::cout<<"--------------------------"<<std::endl;
    }
}

运行结果如下。

绿头鸭:呱呱
红头鸭:呱呱
鸭鸣器:咵咵
橡皮鸭:吱吱
鹅:嘎嘎
绿头鸭:呱呱
绿头鸭:呱呱
绿头鸭:呱呱

绿头鸭:呱呱

绿头鸭:呱呱
绿头鸭:呱呱
绿头鸭:呱呱

绿头鸭:呱呱

6、观察者
这时来了一只斑头秋沙鸭(Mergellus),观察人员对这个新来客很感兴趣,希望单独观察它。
模式步步演化组合使用示例_第5张图片
图6 观察者类图
实现代码如下step_6.h。

#pragma once
#include "step_4.h"
#include <list>

namespace STEP_6
{
    class Observer
    {
    public:
        virtual void Update(STEP_1::Quackable* pDuck) = 0;
    };

    class Quackologist : public Observer
    {
    public:
        virtual void Update(STEP_1::Quackable* pDuck)
        {
            std::cout<<"鸭叫专家观察到鸭叫"<<std::endl;
        }
    };

    class QuackObservable
    {
    public:
        QuackObservable() {}
        virtual ~QuackObservable() {}

        virtual void RegisterObserver(Observer* pObserver) = 0;
        virtual void NotifyObservers() = 0;
    };

    class Observerable : public QuackObservable
    {
    public:
        Observerable(STEP_1::Quackable* pDuck)
            : m_pDuck(pDuck)
        {}

        virtual void RegisterObserver(Observer* pObserver)
        {
            m_Observers.push_back(pObserver);
        }

        virtual void NotifyObservers()
        {
            for (Observer* pObserver : m_Observers)
            {
                pObserver->Update(m_pDuck);
            }
        }

    private:
        std::list<Observer*> m_Observers;
        STEP_1::Quackable* m_pDuck;
    };

    class MergellusDuck : public STEP_1::Quackable, public QuackObservable
    {
    public:
        MergellusDuck()
            : observerable(std::shared_ptr<Observerable>(new Observerable(this)))
        {}
        ~MergellusDuck() {}

        //interface of Quackable
        void quack()
        {
            std::cout<<"斑头秋沙鸭:呱呱"<<std::endl;
            NotifyObservers();
        }

        void MergellusDuck::RegisterObserver(Observer* pObserver)
        {
            observerable->RegisterObserver(pObserver);
        }

        void MergellusDuck::NotifyObservers()
        {
            observerable->NotifyObservers();
        }

    private:
        std::shared_ptr<Observerable> observerable;
    };

    void Test()
    {
        std::shared_ptr<MergellusDuck> duckReal = std::shared_ptr<MergellusDuck>(new MergellusDuck());
        std::shared_ptr<Quackologist> duckViewer = std::shared_ptr<Quackologist>(new Quackologist());
        duckReal->RegisterObserver(duckViewer.get());

        STEP_1::Simulate(duckReal.get());
    }
}

运行结果如下:
斑头秋沙鸭:呱呱
鸭叫专家观察到鸭叫

7、小结
在本例中我们简化使用了多个模式,策略、适配器、装饰者、抽象工厂、组合与迭代器、观察者。模式并不都是重量级应用,轻量级融入我们的代码中,可以得到弹性十足的代码。

你可能感兴趣的:(设计模式,C++)