设计模式之Template Method

栏目: 后端 · 发布时间: 5年前

内容简介:模板模式的主要应用场景为:1、在软件的构造过程种,它常常有稳定的整体操作,但各个子步骤却有着很多改变的需求,或者由于固有的原因二无法与任务的整体框架同时实现;其定义一个操作中的算法骨架,而将一些步骤延迟(变化的部分)到子类中,模板的方法使得子类可以不改变(复用)一个算法的结果即可重定义该算法的某些特定步骤。2、更为通俗的说法是,在父类中实现某个通用的流程,具体小的实现步骤在各个特定的子类中实现,这样加强了代码的复用,但是使用本设计模式的前提是存在一成不变的通用流程。

1、 设计模式 的使用场景

模板模式的主要应用场景为:

1、在软件的构造过程种,它常常有稳定的整体操作,但各个子步骤却有着很多改变的需求,或者由于固有的原因二无法与任务的整体框架同时实现;其定义一个操作中的算法骨架,而将一些步骤延迟(变化的部分)到子类中,模板的方法使得子类可以不改变(复用)一个算法的结果即可重定义该算法的某些特定步骤。

2、更为通俗的说法是,在父类中实现某个通用的流程,具体小的实现步骤在各个特定的子类中实现,这样加强了代码的复用,但是使用本设计模式的前提是存在一成不变的通用流程。

2、具体分析

设计模式之Template Method

从图中可与看出来存在两个抽象类Document、Application,其中Document用于对文档进行各类操作,当然起也是抽象类,因为对于不同的文档需要细化操作细节,我们仅看用于实现抽象操作一个文件的Application类,其具体的操作流程如下所示:

设计模式之Template Method

设计模式之Template Method

首先判断这个文件是否可以被打开,随后使用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();
}

输出结果为:

设计模式之Template Method

可以看到通过在Concretclass1调用从Abstract_class继承的run()方法,成功的使用了子类的重定义的方法,虽说优势不怎么明显哈哈。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序员修炼之道

程序员修炼之道

Andrew Hunt、David Thomas / 马维达 / 电子工业出版社 / 2011-1 / 55.00元

《程序员修炼之道:从小工到专家》内容简介:《程序员修炼之道》由一系列独立的部分组成,涵盖的主题从个人责任、职业发展,知道用于使代码保持灵活、并且易于改编和复用的各种架构技术,利用许多富有娱乐性的奇闻轶事、有思想性的例子及有趣的类比,全面阐释了软件开发的许多不同方面的最佳实践和重大陷阱。无论你是初学者,是有经验的程序员,还是软件项目经理,《程序员修炼之道:从小工到专家》都适合你阅读。一起来看看 《程序员修炼之道》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码