1、设计模式的使用场景
模板模式的主要应用场景为:
1、在软件的构造过程种,它常常有稳定的整体操作,但各个子步骤却有着很多改变的需求,或者由于固有的原因二无法与任务的整体框架同时实现;其定义一个操作中的算法骨架,而将一些步骤延迟(变化的部分)到子类中,模板的方法使得子类可以不改变(复用)一个算法的结果即可重定义该算法的某些特定步骤。
2、更为通俗的说法是,在父类中实现某个通用的流程,具体小的实现步骤在各个特定的子类中实现,这样加强了代码的复用,但是使用本设计模式的前提是存在一成不变的通用流程。
2、具体分析
从图中可与看出来存在两个抽象类Document、Application,其中Document用于对文档进行各类操作,当然起也是抽象类,因为对于不同的文档需要细化操作细节,我们仅看用于实现抽象操作一个文件的Application类,其具体的操作流程如下所示:
首先判断这个文件是否可以被打开,随后使用DoCreateDocument()来产生处理文档的特定类MyDocument,以便实现对不同文件的不同操作,最后通过一系列流程来完成打开过程。值得注意的是OpenDocument()中逻辑过程是稳定的不变的,其中每一步的具体实现是变化的,因此将OpenDocument设置为非虚的成员函数,而将组成OpenDocument的子步骤,也就是CanOpenDocument()、AddDocument()、AboutToOpenDocument()与DoCreateDocument()设置为虚的成员函数。
3、适用性
1、一次性实现一个算法的不变部分,并将可变的行为留给子类来实现;
2、各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;
3、控制子类扩展。
4、注意点
1、使用C++访问控制 在C++中,一个模板方法调用的可变化的那些操作可以被定义为保护成员。这保证他们只在模板方法中被调用(封装原则,反正具体的实现步骤都需要封装在一个特定的对外方法中,如前面的OpenDocument()方法中)。必须被重定义的可变化的成员函数必须被定义为纯虚函数,模板自身不需被重定义;因此将这个模板方法定义为一个非虚成员函数。
2、尽量减少需要重定义的部分 本方法本来就是将主要的工作交给库的设计者(父类),而子类作为直接的方法使用者无需掌握繁杂的使用流程,若需要重定义大量方法不就违反了这个规则。
5、实验代码
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include<iostream>
#include<string>
using std::string;
class Abstract_class
{
public:
Abstract_class(double re = 0, double img = 0) :re(re), img(img)
{};
virtual ~Abstract_class();
void run()
{
step1();
step2();
step3();
step4();
}
private:
double re;
double img;
virtual void step1(string s=" ") = 0;
virtual void step2(string s = " ") = 0;
virtual void step3(string s = " ") = 0;
virtual void step4(string s = " ") = 0;
};
Abstract_class::~Abstract_class()
{
std::cout << "触发Abstract_class析构函数" << std::endl;
}
class Concretclass1:public Abstract_class
{
private:
double re;
double img;
void step1(string s) ;
void step2(string s) ;
void step3(string s) ;
void step4(string s) ;
public:
Concretclass1(double re = 0, double img = 0) :re(re), img(img)
{};
virtual ~Concretclass1()
{
std::cout << "触发Concretclass1析构函数" << std::endl;
};
};
void Concretclass1::step1(string s)
{
std::cout << "this is step1:+:" <<(re+img)<< std::endl;
}
void Concretclass1::step2(string s)
{
std::cout << "this is step2:-:" <<(re - img) << std::endl;
}
void Concretclass1::step3(string s)
{
std::cout << "this is step3:*:" << (re * img) << std::endl;
}
void Concretclass1::step4(string s)
{
std::cout << "this is step4:/:" << (re /img) << std::endl;
}
#endif // !TEMPLATE_H
在代码中我们定义了一个抽象类Abstract_class,这个类中包含一个该子类的通用处理流程run,但是run里面的子实施流程是由各个子类实现的,因此根据之前的说法run方法应该设为public且非虚的,他的子实施流程应该设为private且是虚的(因为外界对象不需要看到这个方法,只需要看到run就行了,增加了封装性)。
在子类Concretclass1中我们实现了这些子实施流程,随后直接使用run()方法就达到目的了。.c文件的内容为:
#include"template.h"
int main()
{
Concretclass1* p1 = new Concretclass1(1.0, 2.0);
p1->run();
delete p1;
std::cin.get();
}
输出结果为:
可以看到通过在Concretclass1调用从Abstract_class继承的run()方法,成功的使用了子类的重定义的方法,虽说优势不怎么明显哈哈。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。