本篇模拟随着需求的变化,模型步步演化,做个杀鸡使用牛刀的组合示例。
参考:设计模式之复合模式。
系统:Windows 7 64位
IDE:VS 2012
1、策略
需求:池塘边有一群红头鸭(RedheadDuck)和绿头鸭(MallarDuck),也有观察人员放置的鸭鸣器(DuckCall),还有附近儿童在玩的橡皮鸭(RubberDuck)。我们需要可视化鸭子叫声。
鸭子叫声:呱呱(quack)
鸭鸣器:咵咵(kwak)
橡皮鸭:吱吱(squeak)
既然叫声如此多种,我们就把叫声做成策略。
类图如下。
图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 适配器类图
实现代码如下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、抽象工厂
观察上述代码,我们发现鸭子创建暴露了太多细节出来,需要计数的时候有可能会忘记进行装饰者包装。
针对这个问题,采用抽象工厂将鸭子创建封装起来。
图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、组合与迭代器
我们需要管理的不止是单个鸭子,而是一群鸭子,此时采用组合来化零为整,采用迭代器来隐藏实现细节将遍历算法固定。
图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),观察人员对这个新来客很感兴趣,希望单独观察它。
图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、小结
在本例中我们简化使用了多个模式,策略、适配器、装饰者、抽象工厂、组合与迭代器、观察者。模式并不都是重量级应用,轻量级融入我们的代码中,可以得到弹性十足的代码。