参考资料:
1. head first 设计模式
2. http://blog.youkuaiyun.com/hguisu/article/details/7558249/
在看设计模式的时候,总觉得好多设计模式都差不多,容易弄混,因此做点记录。
一、模板方法
模板方法模式在一个方法中定义了一个算法的步骤(骨架),而将一些步骤延迟到子类中。模板方法使得子类在不改变算法结构的情况下,重新定义算法中的某些步骤。模板方法模式的一般结构如下图所示:
注:图片来自Head First 设计模式中文版截图
可以看到模板方法模式一般是针对一个算法的各个步骤进行操作,算法的步骤由超类AbstractClass控制,子类ConcreteClass只是实现了父类算法的某几个步骤,本身并不控制算法流程(这点要与下面的策略模式区分)。模板方法模式有几个好处:
- 算法流程只由超类AbstractClass控制,子类无法去修改算法流程(比如算法的执行顺序等,不过可以通过在父类中加入像“钩子”的方法实际上是可以修改算法流程),但是可以修改算法中的某个步骤细节。这样要修改算法比较容易,同时也保护了算法(毕竟只由AbstractClass一个类控制)
- 算法中通用的步骤可以放在超类中实现,利用继承实现了代码复用
举个可能比较牵强的例子,比如我在北京,要回到江西去,有一种路线是:北京->武汉->江西,那么这里 北京->武汉->江西 这个路线流程就是从北京去往江西的一个算法,这个算法分成了两个步骤:北京->武汉,武汉->江西,假设北京到武汉只有高铁,那我只能坐高铁了,但是从武汉到江西既有高铁又有硬座,于是我们设计的代码结构如下:
/**
* 从北京到江西路线算法框架类,确定了整体框架,其中某些步骤需要子类具体实现
* */
public abstract class AbstractFromBeijingToJiangXi {
/**
* 算法框架,定义成final,避免子类去修改算法框架
* */
public final void fromBeijingToJiangXi(){
fromBeijingToWuHan();
fromWuhanToJiangXi();
}
/**
* 这个是算法步骤中变化的步骤,不同的子类有不同的实现
* */
public abstract void fromWuhanToJiangXi();
/**
* 这个是算法的通用步骤,子类不需要实现
* */
public final void fromBeijingToWuHan(){
System.out.println("坐高铁从:北京 -> 武汉");
}
}
以下是两个子类的实现:
/**
* 坐高铁
* */
public class CRHFromBeijingToJiangXi extends AbstractFromBeijingToJiangXi{
/**
* 子类重写的步骤
* */
@Override
public void fromWuhanToJiangXi() {
System.out.println("坐高铁从:武汉 -> 江西 ");
}
}
/**
* 做普通硬座
* */
public class NormalFromBeijingToJiangXi extends AbstractFromBeijingToJiangXi {
@Override
public void fromWuhanToJiangXi() {
System.out.println("坐硬座从:武汉-> 江西 ");
}
}
我们这样使用:
public class Client {
public static void main(String[] args) {
//AbstractFromBeijingToJiangXi road=new CRHFromBeijingToJiangXi();
AbstractFromBeijingToJiangXi road=new NormalFromBeijingToJiangXi();
road.fromBeijingToJiangXi();
}
}
二、策略模式
策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。还是以上面的例子为例,从北京到江西,可以有多种交通方案(每种交通方案相当于一个算法)。得到如下的代码结构:
/**
* 算法族的公共接口
* */
public interface IFromBeijingToJiangXi {
/**
* 不同的算法有不同的实现,子类完全控制算法的步骤流程
* */
public void fromBeijingToJiangXi();
}
子类完全自己实现算法
/**
* 坐高铁
* */
public class CRHFromBeijingToJiangXi implements IFromBeijingToJiangXi{
/**
* 子类自己完全实现算法的流程
* */
@Override
public void fromBeijingToJiangXi() {
fromBeijingToWuHan();
fromWuhanToJiangXi();
}
public void fromBeijingToWuHan(){
System.out.println("坐高铁从:北京-> 武汉 ");
}
public void fromWuhanToJiangXi(){
System.out.println("坐高铁从:武汉->江西 ");
}
}
/**
* 做普通硬座
* */
public class NormalFromBeijingToJiangXi implements IFromBeijingToJiangXi {
/**
* 子类自己完全实现算法的流程
* */
@Override
public void fromBeijingToJiangXi() {
fromBeijingToWuHan();
fromWuhanToJiangXi();
}
public void fromBeijingToWuHan(){
System.out.println("坐硬座从:北京-> 武汉 ");
}
public void fromWuhanToJiangXi(){
System.out.println("坐硬座从:武汉->江西 ");
}
}
如何使用:
public class Client {
private IFromBeijingToJiangXi fromBeijingToJiangXi;
public Client(IFromBeijingToJiangXi fromBeijingToJiangXi){
this.fromBeijingToJiangXi=fromBeijingToJiangXi;
}
public void travel(){
fromBeijingToJiangXi.fromBeijingToJiangXi();
}
public static void main(String[] args) {
//客户端使用时需要事先知道对应的具体的算法
IFromBeijingToJiangXi fromBeijingToJiangXi=new CRHFromBeijingToJiangXi();
//可以换不同的算法
//IFromBeijingToJiangXi fromBeijingToJiangXi=new NormalFromBeijingToJiangXi();
Client client=new Client(fromBeijingToJiangXi);
client.travel();
}
}
三、 二者的区别
1. 二者针对的对象的粒度不同,给我感觉模板方法模式是以算法的步骤为单位,而策略模式是以算法为单位
2. 模板方法模式的子类只修改了算法的某些步骤,并不会去改变算法的框架流程,而策略模式的子类则自己完全定义了算法的步骤和流程