设计模式:模板模式 CRTP设计习语

一、模板模式

1、模板模式

1)定义

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

2)动机(motivation)

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

> 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

结构化软件设计流程:

面向对象软件设计流程:

 

3)类图

 AbstractClass是抽象类,也是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法。

ConCreteClass,实现父类所定义的一个或多个抽象方法。每个AbstractClass都可以有任意多个ConCreteClass与之对应,而每一个ConCreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

4)代码实现

#include <iostream>
#include <string>
#include<memory>
using namespace std;

class Library
{
public:
	void run() //template method
	{
		step1();
		while (!step2()) //多态调用
			step3();
		step4(); //多态调用
		step5();
	}
	virtual ~Library() {}

protected:
	void step1()
	{
		cout << "Library.step1()" << endl;
	}

	void step3()
	{
		cout << "Library.step3()" << endl;
	}

	void step5()
	{
		cout << "Library.step5()" << endl;
	}

protected:
	int number{ 0 };

private: //NVI: Non-Virtual Interface
	virtual bool step2() = 0;
	virtual int step4() = 0;
};

class App : public Library
{
private:
	bool step2() override
	{
		//Library::step2();//静态绑定
		cout << "App.step2()" << endl;
		number++;
		return number >= 3;
	}

	int step4() override
	{
		cout << "App.step4() : " << number << endl;
		return number;
	}
};

int main()
{
	std::unique_ptr<Library> library = std::make_unique<App>();

	//1. 存储成本:虚表指针 + 虚表结构(共享)
	//2. 调用成本: 间接指针辨析, 无法inline
	library->run();

	system("pause");
	return 0;
}

5)要点总结

> Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。

> 除了可以灵活对应子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。

> 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将他们设置为protected或private方法(公有接口非虚NVI,Non-Virtual Interface)。

二、CRTP习语

1、CRTP

1)定义

CRTP(Curious Recurring Template Pattern):奇异递归模板模式。通过将基类模板参数设置为子类,从而实现静态多态(静态接口),或者扩展接口(委托实现)。

2)要点

> class Sub:public Base<Sub>通过模板参数,将子类类型在编译时注入基类,从而实现在基类中提前获取子类类型信息。

> static_cast<T*>(this)将基类指针转型为模板子类T的指针。

> Base类型为不完整类型,不能使用Sub参与内存布局,但可以在函数内使用(发生调用,模板编译时辨析即可)。

> 删除对象,也要使用编译时多态进行删除,避免直接delete。

3)代码实现

#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <vector>
using namespace std;

template <typename T>
class Library
{
public:
	void run() //template method
	{
		step1();
		while (!sub()->step2()) //子类调用
			step3();
		sub()->step4(); //子类调用
		step5();
	}

	void destroy()
	{
		delete sub();
	}
protected:
	T* sub() {
		return static_cast<T*>(this);
	}
	void step1()
	{
		cout << "Library.step1()" << endl;
	}

	void step3()
	{
		cout << "Library.step3()" << endl;
	}

	void step5()
	{
		cout << "Library.step5()" << endl;
	}
protected:
	int number{ 0 };

	bool step2() { return false; }
	int step4() { return 0; }
public:
	~Library() {
		cout << "Library dtor" << endl;
	}
};

class App : public Library<App>
{
public:
	bool step2()
	{
		cout << "App.step2()" << endl;
		number++;
		return number >= 3;
	}
	int step4()
	{
		cout << "App.step4() : " << number << endl;
		return number;
	}

	~App() {
		cout << "App dtor" << endl;
	}
};

template<typename T>
void invoke(Library<T> &lib)
{
	lib.run();
}

int main()
{
	{
		Library<App> *pLib = new App();
		pLib->run();
		pLib->destroy();
		cout << endl;
	}

	cout << "----------------------------" << endl;
	{
		auto lambda = [](auto p) { p->destroy(); };
		unique_ptr<Library<App>, decltype(lambda)> uptr(new App(), lambda);
		uptr->run();
	}
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
写一段JQuery 实现以下逻辑 var hd =$('#txtHeadRailQty').val();// 这个是Common ValanceHeadRail Number: if(hd == 2) //HeadRail Number:2 var cm =$('#CommonValance').val(); //这个是Blind Type if(cm == 'Common Valance') //Blind Type為Common Valance var mt= $('#txtMeasuringType').val()// 这个为WS 或者MFF if(mt =='WS') 这个为WS if(mt == 'MFF') 这个为MFF var lw =$('#txtLeftWidth').val();//这个是Left Width var ltp =$('#txtLeftTiltPos').val(); 这个是Left Width 对应的wand var cw =$('#txtCenterWidth').val();这个 是Center Left Width var ltp =$('#txtCenterTiltPos').val(); 这个是Center Left Width 对应的wand var cwb =$('#txtCenterWidthB').val();//这个是Center Right Width var ltp =$('#txtCenterTiltPosB').val(); 这个是Center Right Width 对应的wand var rw =$('#txtRightWidth').val();//这个是Right Width var ltp =$('#txtRightTiltPos').val(); 这个是Right Width 对应的wand var lgw = $('#txtLeftGapWidth').val() // 这个是Left Gap Width var rgw =$('#txtRightGapWidth').val() //这个是Right Gap Width var cgw = $('#txtCenterGapWidth').val() // 这个是Center Gap Width HeadRail Number:2,WS時 Left Width在 165mm+5mm+Left Gap Width/2~380+5mm+Left Gap Width/2時,Wand值需顯示C Right Width在 165mm+5mm+Left Gap Width/2~380+5mm+Left Gap Width/2時,Wand值需顯示C HeadRail Number:3,WS時 Left Width在 165mm+5mm+Left Gap Width/2~380+5mm+Left Gap Width/2時,Wand值需顯示C Center Width 在 165mm+Left Gap Width/2+Right Gap Width/2~380+Left Gap Width/2+Right Gap Width/2 時,Wand值需顯示C Right Width在 165mm+5mm+ Right Gap Width/2~380+5mm+ Right Gap Width/2時,Wand值需顯示C HeadRail Number:4,WS時 Left Width在 165mm+5mm+Left Gap Width/2~380+5mm+Left Gap Width/2時,Wand值需顯示C Center Left Width 在 165mm+Left Gap Width/2+ Center Gap Width/2~380+Left Gap Width/2+ Center Gap Width/2時,Wand值需顯示C Center Right Width 在 165mm+ Center Gap Width/2+ Right Gap Width/2~380+ Center Gap Width/2+ Right Gap Width/2時,Wand值需顯示C Right Width在 165mm+5mm+ Right Gap Width/2~380+5mm+ Right Gap Width/2時,Wand值需顯示C HeadRail Number:2,MFF時 Left Width在 165mm+Left Gap Width/2~380+Left Gap Width/2時,Wand值需顯示C Right Width在 165mm+Left Gap Width/2~380+Left Gap Width/2時,Wand值需顯示C HeadRail Number:3,MFF時 Left Width在 165mm+Left Gap Width/2~380+Left Gap Width/2時,Wand值需顯示C Center Width 在 165mm+Left Gap Width/2+Right Gap Width/2~380+Left Gap Width/2+Right Gap Width/2 時,Wand值需顯示C Right Width在 165mm+ Right Gap Width/2~380+ Right Gap Width/2時,Wand值需顯示C HeadRail Number:4,MFF時 Left Width在 165mm+Left Gap Width/2~380+Left Gap Width/2時,Wand值需顯示C Center Left Width 在 165mm+Left Gap Width/2+ Center Gap Width/2~380+Left Gap Width/2+ Center Gap Width/2時,Wand值需顯示C Center Right Width 在 165mm+ Center Gap Width/2+ Right Gap Width/2~380+ Center Gap Width/2+ Right Gap Width/2時,Wand值需顯示C Right Width在 165mm+ Right Gap Width/2~380+ Right Gap Width/2時,Wand值需顯示C
06-13

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值