我是靠谱客的博主 等待百合,这篇文章主要介绍23种设计模式(二)组件协作之模板方法,现在分享给大家,希望可以做个参考。

本系列所有文章来自李建忠老师的设计模式笔记,系列如下:
设计模式(一)面向对象设计原则
23种设计模式(二)组件协作之模板方法
23种设计模式(三)组件协作之策略模式
23种设计模式(四)组件协作之观察者模式
23种设计模式(五)单一职责之装饰模式
23种设计模式(六)单一职责之桥模式
23种设计模式(七)对象创建之工厂方法
23种设计模式(八)对象创建之抽象工厂
23种设计模式(九)对象创建之原型模式
23种设计模式(十)对象创建之构建器
23种设计模式(十一)对象性能之单件模式
23种设计模式(十二)对象性能之享元模式
23种设计模式(十三)接口隔离之门面模式
23种设计模式(十四)接口隔离之代理模式
23种设计模式(十五)接口隔离之适配器
23种设计模式(十六)接口隔离之中介者
23种设计模式(十七)状态变化之状态模式
23种设计模式(十八)状态变化之备忘录
23种设计模式(十九)数据结构之组合模式
23种设计模式(二十)数据结构之迭代器
23种设计模式(二十一)数据结构之职责链
23种设计模式(二十二)行为变化之命令模式
23种设计模式(二十三)行为变化之访问器
23种设计模式(二十四)领域规则之解析器

文章目录

    • Template Method 模式
    • 设计方法一
    • 设计方法二
    • 两种方法对比
    • 模式定义

  23种设计模式主要可以分为以下几类:

  • 从目的来看

创建型(Creational)模式:将对象的部分创建工作延迟到子类或者其他对象,从而应对需求变化为对象创建时具体类型实现引来的冲击。

结构型(Structural)模式:通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击。

行为型(Behavioral)模式:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击。

  • 从范围来看

  类模式处理类与子类的静态关系。
  对象模式处理对象间的动态关系。

  • 从封装变化角度对模式分类

  面向对象设计模式是“好的面向对象设计”,所谓“好的面向对象设计”指是那些可以满足“应对变化,提高复用”的设计

  现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点,然后在变化点处应用设计模式,从而来更好地应对需求的变化”.“什么时候、什么地点应用设计模式”比“理解设计模式结构本身”更为重要。

  不光是写代码,看代码也需要看到代码的变化部分,与不变部分。

  设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。敏捷软件开发实践提倡的“Refactoring to Patterns”(重构设计模式)是目前普遍公认的最好的使用设计模式的方法。

Template Method 模式

  在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。

设计方法一

  先举个例子看一下:

  • template1_lib.cpp
//程序库开发人员
class Library{

public:
	void Step1(){
		//...
	}

    void Step3(){
		//...
    }

    void Step5(){
		//...
    }
};
  • template1_app.cpp
//应用程序开发人员
class Application{
public:
	bool Step2(){
		//...
    }

    void Step4(){
		//...
    }
};

int main()
{
	Library lib();
	Application app();

	lib.Step1();

	if (app.Step2()){
		lib.Step3();
	}

	for (int i = 0; i < 4; i++){
		app.Step4();
	}

	lib.Step5();

}

  上述的main函数执行的流程常常是不需要更改且是稳定的。

  上面是一种做法,接下来看一下第二种做法:

设计方法二

  • template2_lib.cpp
//程序库开发人员
class Library{
public:
	//稳定 template method
    void Run(){
        
        Step1();

        if (Step2()) { //支持变化 ==> 虚函数的多态调用
            Step3(); 
        }

        for (int i = 0; i < 4; i++){
            Step4(); //支持变化 ==> 虚函数的多态调用
        }

        Step5();

    }
	virtual ~Library(){ }

protected:
	
	void Step1() { //稳定
        //.....
    }
	void Step3() {//稳定
        //.....
    }
	void Step5() { //稳定
		//.....
	}

	virtual bool Step2() = 0;//变化
    virtual void Step4() =0; //变化
};

  这里的框架开发人员完全可以把这个主函数的流程给写下来。

  • template2_app.cpp
//应用程序开发人员
class Application : public Library {
protected:
	virtual bool Step2(){
		//... 子类重写实现
    }

    virtual void Step4() {
		//... 子类重写实现
    }
};

int main()
	{
	    Library* pLib=new Application();
	    lib->Run();

		delete pLib;
	}
}

  Library* pLib=new Application();是一个多态指针,他的声明类型是一个Library, 但是实际类型是Application,当它调用虚函数的时候就会按照虚函数的动态绑定规则去调用。

  在c++里面写一个基类的话,有一条原则就是应该把这个基类里面的析构函数写成虚的。如果不写成虚的,那么Library* pLib=new Application();这行代码就调用不到子类的析构函数。

两种方法对比

  第一种方法是结构化的软件设计流程

  • 结构化软件设计流程

结构化软件设计流程

  • 面向对象软件设计流程

  这两种设计方法主要的不同之处在于早绑定与晚绑定:

  Library一般写地早,Application写地比较晚,当一个写地比较晚的东西调用一个写地比较早的东西,这就是早绑定。这是所有编程语言都比较默认的做法。在面向对象编程里面有一种叫做晚绑定的机制,Library调用Application, 一个早的东西调用一个晚的东西,这就叫做晚绑定。

模式定义

  定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。

  通俗一点来说就是定义一个虚函数,让子类去实现这个虚函数。延迟到子类也就是支持子类变化。

最后

以上就是等待百合最近收集整理的关于23种设计模式(二)组件协作之模板方法的全部内容,更多相关23种设计模式(二)组件协作之模板方法内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部