应用场景:在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现) 在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。 Template 提供了这种情况的一个实现框架。
Template模式是采用继承的方式作为强制约束实现这一点:将逻辑(算法)框架放在抽象基类中, 并定义好细节的接口,子类中实现细节。
Strategy 模式解决的是和 Template 模式类似的问题;Strategy 模式是将逻辑(算法)封装到一个类中,并采取组合(委托)的方式解决这个问题。

实现:
- Template.h
#ifndef _TEMPLATE_H_
#define _TEMPLATE_H_
class AbstractClass
{
public:
virtual ~AbstractClass();
void TemplateMethod();
protected:
virtual void PrimitiveOperation1() = 0;
virtual void PrimitiveOperation2() = 0;
AbstractClass();
private:
};
class ConcreteClass1:public AbstractClass
{
public:
ConcreteClass1();
~ConcreteClass1();
protected:
void PrimitiveOperation1();
void PrimitiveOperation2();
private:
};
class ConcreteClass2:public AbstractClass
{
public:
ConcreteClass2();
~ConcreteClass2();
protected:
void PrimitiveOperation1();
void PrimitiveOperation2();
private:
};
#endif
- Template.cpp
#include "Template.h"
#include <iostream>
using namespace std;
AbstractClass::AbstractClass(){}
AbstractClass::~AbstractClass(){}
void AbstractClass::TemplateMethod()
{
this->PrimitiveOperation1();
this->PrimitiveOperation2();
}
ConcreteClass1::ConcreteClass1(){}
ConcreteClass1::~ConcreteClass1(){}
void ConcreteClass1::PrimitiveOperation1()
{
cout<<"ConcreteClass1...PrimitiveOperation1"<<endl;
}
void ConcreteClass1::PrimitiveOperation2()
{
cout<<"ConcreteClass1...PrimitiveOperation2"<<endl;
}
ConcreteClass2::ConcreteClass2(){}
ConcreteClass2::~ConcreteClass2(){}
void ConcreteClass2::PrimitiveOperation1()
{
cout<<"ConcreteClass2...PrimitiveOperation1"<<endl;
}
void ConcreteClass2::PrimitiveOperation2()
{
cout<<"ConcreteClass2...PrimitiveOperation2"<<endl;
}
3.main.cpp
#include "Template.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
AbstractClass* p1 = new ConcreteClass1();
AbstractClass* p2 = new ConcreteClass2();
p1->TemplateMethod();
p2->TemplateMethod();
return 0;
}
总结:
(1)Template 模式是很简单模式,但是也应用很广的模式。如上面的分析和实现中阐明的Template 是采用继承的方式实现算法的异构,其关键点就是将通用算法封装在抽象基类中,并将不同的算法细节放到子类中实现。 (2)Template 模式获得一种反向控制结构效果, 这也是面向对象系统的分析和设计中一个原则 DIP(依赖倒置: Dependency Inversion Principles)。 其含义就是父类调用子类的操作(高层模块调用低层模块的操作),低层模块实现高层模块声明的接口。这样控制权在父类(高层模块),低层模块反而要依赖高层模块。 (3)不足:基于继 承 的 强 制 性 约 束 关 系 , 我 们 可 以 看 到 对 于ConcreteClass 类中的实现的原语方法 Primitive1(),是不能被别的类复用。Template 模式暴露的问题也正是继承所固有的问题, Strategy 模式则通过组合(委托)来达到和 Template 模式类似的效果, 其代价就是空间和时间上的代价。
Strategy 模式将逻辑(算法) 封装到一个类( Context)里面, 通过组合的方式将具体算法的实现在组合对象中实现, 再通过委托的方式将抽象接口的实现委托给组合对象实现。

将算法的逻辑抽象接口( DoAction)封装到一个类中( Context),再通过委托的方式将具体的算法实现委托给具体的 Strategy 类来实现( ConcreteStrategeA类)。
实现:
1.Strategy.h
#ifndef _STRATEGY_H_
#define _STRATEGY_H_
class Strategy
{
public:
Strategy();
virtual ~Strategy();
virtual void AlgrithmInterface() = 0;
};
class ConcreteStrategyA:public Strategy
{
public:
ConcreteStrategyA();
virtual ~ConcreteStrategyA();
void AlgrithmInterface();
};
class ConcreteStrategyB:public Strategy
{
public:
ConcreteStrategyB();
virtual ~ConcreteStrategyB();
void AlgrithmInterface();
};
#endif
2.Strategy.cpp
#include "Strategy.h"
#include <iostream>
using namespace std;
Strategy::Strategy(){}
Strategy::~Strategy()
{
cout<<"~Strategy....."<<endl;
}
void Strategy::AlgrithmInterface()
{}
ConcreteStrategyA::ConcreteStrategyA()
{}
ConcreteStrategyA::~ConcreteStrategyA()
{
cout<<"~ConcreteStrategyA....."<<endl;
}
void ConcreteStrategyA::AlgrithmInterface()
{
cout<<"test ConcreteStrategyA....."<<endl;
}
ConcreteStrategyB::ConcreteStrategyB()
{}
ConcreteStrategyB::~ConcreteStrategyB()
{
cout<<"~ConcreteStrategyB....."<<endl;
}
void ConcreteStrategyB::AlgrithmInterface()
{
cout<<"test ConcreteStrategyB....."<<endl;
}
3.Context.h
#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class Strategy;
/**
*这个类是 Strategy 模式的关键,也是 Strategy 模式和 Template 模式的根本区别所在。
*Strategy 通过“组合”(委托) 方式实现算法(实现) 的异构,而 Template 模式则采取的是继承的方式
*这两个模式的区别也是继承和组合两种实现接口重用的方式的区别
**/
class Context
{
public:
Context(Strategy* stg);
~Context();
void DoAction();
private:
Strategy* _stg;
};
#endif
4.Context.cpp
//Client.c
//Context.cpp
#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;
Context::Context(Strategy* stg)
{
_stg = stg;
}
Context::~Context()
{
if (!_stg)
delete _stg;
}
void Context::DoAction()
{
_stg->AlgrithmInterface();
}
5.main.cpp
#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Strategy* ps = new ConcreteStrategyA();
Context* pc = new Context(ps);
pc->DoAction();
if (NULL != pc)
delete pc;
return 0;
}
总结:
(1)Strategy 模式和 Template 模式实际是实现一个抽象接口的两种方式: 继承和组合之间的区别。 要实现一个抽象接口, 继承是一种方式: 我们将抽象接口声明在基类中, 将具体的实现放在具体子类中。 组合(委托) 是另外一种方式: 我们将接口的实现放在被组合对象中,将抽象接口放在组合类中。
(2)继承方式:易于修改和扩展那些实现(类中具体的操作函数),但是
破坏力封装的特性,父类的实现细节暴露给子类;
父类发生改变,所有子类都要改变;
父类继承来的实现--------------------------静多态(编译时期确定)
(3)组合方式:封装性好,内部细节外部不可见;组合对象和非组合对象之间依赖性小;可以在运行期间动态定义实现(通过抽象基类的指针)
系统中对象过多;
|