模板模式
定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。
简单示例
//抽象类(基类)
class AbstractClass
{
public:
//模板方法,定义一个算法的框架流程
void templateMethod(){
//do something
method1();
method2();
method3();
}
protected://声明为protected重要
//公共方法
void method1(){
//do something
}
//子类必须实现的方法
virtual void method2()=0;
//默认实现
virtual void method3(){
//do something
}
};
//具体类(派生类)
class ConcreteClass:public AbstractClass
{
protected://注意声明为protected
//实现方法2
void method2(){
//do something
}
//重定义方法3
void method3(){
//do something
}
};
场景示例
#include <iostream>
using namespace std;
//基类
class FingerprintModule
{
public:
FingerprintModule() {}
virtual ~FingerprintModule() {}
void algorithm()
{
//1.采图
getImage();
//2.安全模式下加密和解密
if (isSafeMode())
{
//2.1.加密
encrypt();
//2.2.解密
decrypt();
}
//3.处理Image
processImage();
//4.处理结果
output();
}
protected:
void getImage()
{
printf("采指纹图像\n");
}
void output()
{
printf("指纹图像处理完成!\n");
}
virtual bool isSafeMode() = 0;
virtual void processImage() = 0;
//加解密
virtual void encrypt() = 0;
virtual void decrypt() = 0;
};
//派生类
class FingerprintModuleA :public FingerprintModule
{
public:
FingerprintModuleA() {}
virtual ~FingerprintModuleA() {}
protected:
void processImage()
{
printf("使用 第一代版本算法 处理指纹图像\n");
}
bool isSafeMode()
{
printf("安全模式\n");
return true;
}
void encrypt()
{
printf("使用RSA密钥加密\n");
}
void decrypt()
{
printf("使用RSA密钥解密\n");
}
};
// 派生类
class FingerprintModuleB :public FingerprintModule
{
public:
FingerprintModuleB() {}
virtual ~FingerprintModuleB() {}
protected:
void processImage()
{
printf("使用 第二代版本算法 处理指纹图像\n");
}
bool isSafeMode()
{
printf("非安全模式\n");
return false;
}
void encrypt() {}
void decrypt() {}
};
// 派生类
class FingerprintModuleC :public FingerprintModule
{
public:
FingerprintModuleC() {}
virtual ~FingerprintModuleC() {}
protected:
void processImage()
{
printf("使用 第一代版本算法 处理指纹图像\n");
}
bool isSafeMode()
{
printf("安全模式\n");
return true;
}
void encrypt()
{
printf("使用DH密钥加密\n");
}
void decrypt()
{
printf("使用DH密钥解密\n");
}
};
void main()
{
FingerprintModule *fpA = new FingerprintModuleA();
fpA->algorithm();
printf("\n");
FingerprintModule *fpB = new FingerprintModuleB();
fpB->algorithm();
printf("\n");
FingerprintModule *fpC = new FingerprintModuleC();
fpC->algorithm();
printf("\n");
if (fpA) delete fpA;
if (fpB) delete fpB;
if (fpC) delete fpC;
}
策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。
简单示例
#include <iostream>
using namespace std;
//the abstract strategy
class Strategy
{
public:
Strategy() {}
virtual ~Strategy() {}
//定义为public的方法
virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA :public Strategy
{
public :
ConcreteStrategyA() {}
virtual ~ConcreteStrategyA(){}
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyA." << endl;
}
};
class ConcreteStrategyB :public Strategy
{
public:
ConcreteStrategyB() {}
virtual ~ConcreteStrategyB() {}
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyB." << endl;
}
};
class ConcreteStrategyC :public Strategy
{
public:
ConcreteStrategyC() {}
virtual ~ConcreteStrategyC() {}
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyC." << endl;
}
};
class Context
{
public:
Context(Strategy *pStrategyArg) :pStrategy(pStrategyArg)
{}
virtual ~Context() {}
void ContextInterface()
{
pStrategy->AlgorithmInterface();
}
private:
Strategy *pStrategy;
};
void main()
{
Strategy *pStrategyA = new ConcreteStrategyA;
Strategy *pStrategyB = new ConcreteStrategyB;
Strategy *pStrategyC = new ConcreteStrategyC;
Context *pContextA = new Context(pStrategyA);
Context *pContextB = new Context(pStrategyB);
Context *pContextC = new Context(pStrategyC);
pContextA->ContextInterface();
pContextB->ContextInterface();
pContextC->ContextInterface();
if (pContextA) delete pContextA;
if (pContextB) delete pContextB;
if (pContextC) delete pContextC;
if (pStrategyA) delete pStrategyA;
if (pStrategyB) delete pStrategyB;
if (pStrategyC) delete pStrategyC;
}
策略模式和简单工厂模式相结合
#include <iostream>
using namespace std;
//Define the strategy type
typedef enum StrategyType
{
StrategyA,
StrategyB,
StrategyC
}STRATEGYTYPE;
//the abstract strategy
class Strategy
{
public:
Strategy() {}
virtual ~Strategy() {}
//定义为public的方法
virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA :public Strategy
{
public :
ConcreteStrategyA() {}
virtual ~ConcreteStrategyA(){}
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyA." << endl;
}
};
class ConcreteStrategyB :public Strategy
{
public:
ConcreteStrategyB() {}
virtual ~ConcreteStrategyB() {}
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyB." << endl;
}
};
class ConcreteStrategyC :public Strategy
{
public:
ConcreteStrategyC() {}
virtual ~ConcreteStrategyC() {}
void AlgorithmInterface()
{
cout << "I am from ConcreteStrategyC." << endl;
}
};
class Context
{
public:
Context(STRATEGYTYPE strategyType)
{
switch (strategyType)
{
case StrategyA:
pStrategy = new ConcreteStrategyA;
break;
case StrategyB:
pStrategy = new ConcreteStrategyB;
break;
case StrategyC:
pStrategy = new ConcreteStrategyC;
break;
default:
break;
}
}
virtual ~Context()
{
if (pStrategy)
{
delete pStrategy;
}
}
void ContextInterface()
{
if (pStrategy)
pStrategy->AlgorithmInterface();
}
private:
Strategy *pStrategy;
};
void main()
{
Context *pContext = new Context(StrategyB);
pContext->ContextInterface();
if (pContext)delete pContext;
}
场景示例
#include <iostream>
using namespace std;
//Define the strategy type
typedef enum StrategyType
{
StrategyA,
StrategyB,
StrategyC
}STRATEGYTYPE;
//the abstract strategy
class Strategy
{
public:
Strategy() {}
virtual ~Strategy() {}
//定义为public的方法
virtual void sort(int arr[],int N) = 0;
};
//具体策略类:冒泡排序
class BubbleSort :public Strategy
{
public :
BubbleSort()
{
printf("冒泡排序\n");
}
virtual ~BubbleSort(){}
void sort(int arr[],int N)
{
for (int i = 0;i < N;++i)
{
for (int j = 0;j < N - i - 1;++j)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
};
//具体策略类:选择排序
class SelectionSort :public Strategy
{
public:
SelectionSort()
{
printf("选择排序\n");
}
virtual ~SelectionSort() {}
void sort(int arr[],int N)
{
int i, j, k;
for (i = 0;i < N;++i)
{
k = i;
for (j = i + 1;j < N;++j)
{
if (arr[j] < arr[k])
{
k = j;
}
}
int temp = arr[i];
arr[i] = arr[k];
arr[k] = temp;
}
}
};
//具体策略类:插入排序
class InsertSort :public Strategy
{
public:
InsertSort()
{
printf("插入排序\n");
}
virtual ~InsertSort() {}
void sort(int arr[],int N)
{
int i, j;
for (i = 1;i < N;++i)
{
int tmp = arr[i];
for (j = i - 1;j >= 0;--j)
{
if (tmp < arr[j])
{
arr[j + 1] = arr[j];
}
else
{
break;
}
}
arr[j + 1] = tmp;
}
}
};
//上下文类
class Context
{
public:
Context()
{
arr = NULL;
N = 0;
}
Context(int iArr[], int iN)
{
this->arr = iArr;
this->N = iN;
}
virtual ~Context()
{
}
void setSortStrategy(Strategy *iSortStrategy)
{
this->sortStrategy = iSortStrategy;
}
void sort()
{
this->sortStrategy->sort(arr, N);
printf("输出: ");
this->print();
}
void setInput(int iArr[], int iN)
{
this->arr = iArr;
this->N = iN;
}
void print()
{
for (int i = 0;i < N;++i)
{
printf("%4d", arr[i]);
}
printf("\n");
}
private:
Strategy *sortStrategy;
int *arr;
int N;
};
void main()
{
Context *ctx = new Context();
int arr[] = { 10,23,-1,0,300,87,28,77,-32,2 };
ctx->setInput(arr, sizeof(arr) / sizeof(int));
printf("输入:");
ctx->print();
//冒泡排序
ctx->setSortStrategy(new BubbleSort());
ctx->sort();
//选择排序
ctx->setSortStrategy(new SelectionSort());
ctx->sort();
//插入排序
ctx->setSortStrategy(new InsertSort());
ctx->sort();
printf("\n\n");
}
模板方法模式和策略模式之间的区别
两者的主要区别在于具体算法的选择:
通过模板方法模式,这通过子类化模板在编译时发生。每个子类通过实现模板的抽象方法提供了不同的具体算法。当客户端调用模板外部接口的方法时,模板根据需要调用其抽象方法(其内部接口)来调用算法。
相比之下,策略模式允许在运行时通过遏制来选择算法。具体的算法是通过单独的类或函数来实现的,这些类或函数作为其构造函数或设置方法的参数传递给策略。该参数选择哪种算法可以根据程序的状态或输入动态变化。
综上所述:
- 模板方法模式:通过子类化来编译时间算法选择
- 策略模式:通过遏制运行时算法选择
以下摘自策略模式和模版模式的异同
Strategy模式的应用场景是:
- 多个类的分别只是在于行为不同
- 你需要对行为的算法做很多变动
- 客户不知道算法要使用的数据
Template Method模式的应用场景是:
- 你想将相同的算法放在一个类中,将算法变化的部分放在子类中实现
- 子类公共的算法应该放在一个公共的类中,避免代码重复
我们知道,设计模式中有这么一个原则:Prefer composition to inheritance,这句话的背景是OO初期大家都把继承看作是万能的,并过度使用继承来实现多态->可扩展。
理解原则的时候不能脱离它的背景,不然就成盲从了.Template Method模式应该是伴随着OO的出现而萌生的。它是OO中最直观的思考方式的结果,基类留下可变化的空间给子类,由继承类来决定具体行为。听起来是不错,不过…一旦基类的接口发生了变化,每个继承类都得跟着修改才能够继续使用。这就是所谓高耦合与难维护的说法的来源。
Strategy与Template Method模式算是composition与inheritance的典型应用了。
GoF的设计模式那本书里有这么一句话:“Template methods use inheritance to vary part of an algorithm. Strategies use delegation to vary the entire algorithm.”,说的正是这个问题。回到具体问题上,如果我们要封装的算法适合于提供给用户任意使用,是"一整个算法",那么用Strategy模式较好;如果要封装的变化是一个算法中的部分(换言之,大算法的步骤是固定的),而且我们不希望用户直接使用这些方法,那么应该使用Templa Method模式。