您的位置:首页 > 其它

设计模式——模板方法模式(Template Method)

2012-03-12 13:56 483 查看
模板方法属于行为型设计模式,行为型设计模式主要关注对象之间职责分配和算法的问题。类行为型模式使用继承来分配类之间的职责,模板方法就是个类行为型模式。对象行为型模式使用组合来分配职责。在我们构建软件的过程中大部分时候我们都是在思考实体之间的职责,怎样的职责分配最合理,不至于过重,又不至于过轻,而且又不越权。

定义

在一个方法里定义算法的骨架,将一些步骤延迟到其子类。模板方法使得子类有机会重新定义算法的某些步骤而不改变算法的结构。

模板方法实际上是利用多态这种晚绑定机制来将一些执行系列延迟到子类(运行时)。如下图:




模板方法模式确实非常简单,仅仅使用继承机制,但是它是一个应用非常广泛的模式。其中,AbstractClass叫做抽象模板,它的方法分为两类:

基本方法

基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法被调用。

模板方法

可以有一个或几个,一般是一个具体方法,也就是一个骨架,实现对基本方法的调度,完成固定的逻辑。

注意为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写。

在类图中还有一个角色:具体模板,ConcreteClass1和ConcreteClass2属于具体模板,实现父类所定义的一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现。

钩子的定义:钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。究竟需不需要挂钩,则由子类自行决定。

实例

我们有一个咖啡厅,有一个专门的配方来调制咖啡喝茶,在调制的过程中的某些方法其实是比较类似的,步骤如下:

1、把水煮沸

2、用热水泡咖啡或茶

3、把饮料倒进杯子

4、在饮料内加入适当的调料,咖啡要加糖和牛奶,而茶需要加柠檬。在调料添加的时候,我们需要询问顾客是否需要添加调料,此时就会用到钩子。

类图:



c++代码如下:
#include <iostream>
using namespace std;

class CaffeineBeverage
{
public:
void prepareRecipe();
private:
virtual void brew() = 0;
virtual void addCondiments() = 0;
void boilWater();
void pourInCup();
virtual bool customerWantsCondiments(); // 钩子
};

class Coffee : public CaffeineBeverage
{
private:
void brew();
void addCondiments();
bool customerWantsCondiments();
};

class Tea : public CaffeineBeverage
{
private:
void brew();
void addCondiments();
bool customerWantsCondiments();
};

void CaffeineBeverage::prepareRecipe()
{
boilWater();
brew();
pourInCup();
if (customerWantsCondiments())
{
addCondiments();
}
}

void CaffeineBeverage::boilWater()
{
printf("把水煮沸\n");
}

void CaffeineBeverage::pourInCup()
{
printf("倒入杯子中\n");
}

bool CaffeineBeverage::customerWantsCondiments()
{
return true;
}

void Coffee::brew()
{
printf("用沸水冲泡咖啡粉\n");
}

void Coffee::addCondiments()
{
printf("加糖和牛奶\n");
}

bool Coffee::customerWantsCondiments()
{
char zAnswer;
printf("您的咖啡中是否需要牛奶和糖:");
fflush(stdin);
zAnswer = getchar();
zAnswer = toupper(zAnswer);
if ('Y'==zAnswer)
{
return true;
}
else if ('N'==zAnswer)
{
return false;
}
else
{
printf("输入错误,默认不加调料\n");
return false;
}
}

void Tea::brew()
{
printf("用沸水浸泡茶叶\n");
}
void Tea::addCondiments()
{
printf("加柠檬\n");
}

bool Tea::customerWantsCondiments()
{
char zAnswer;
printf("您的茶中是否需要柠檬:");
fflush(stdin);
zAnswer = getchar();
zAnswer = toupper(zAnswer);
if ('Y'==zAnswer)
{
return true;
}
else if ('N'==zAnswer)
{
return false;
}
else
{
printf("输入错误,默认不加调料\n");
return false;
}
}

int main()
{
Coffee coffee;
Tea tea;
coffee.prepareRecipe();
tea.prepareRecipe();
return 0;
}


运行结果:

把水煮沸

用沸水冲泡咖啡粉

倒入杯子中

您的咖啡中是否需要牛奶和糖:y

加糖和牛奶

把水煮沸

用沸水浸泡茶叶

倒入杯子中

您的茶中是否需要柠檬:n

解说

模板方法模式是一个很常见的模式,到处都是。在实际应用中,模板方法有许多的实现,而它们看起来并不一定和书上所讲的设计一致。这个设计常见,是因为对创建框架来说,这个模式简直棒极了,由框架控制如何做事情,而由使用框架的人来指定框架算法中的每个步骤的细节。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: