Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.(定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。)
模板方法介绍
核心是实现钩子函数,通用类图如下所示:
其中Abstract类是抽象类,其实也就是一抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体的方法,它给出了一个顶级的逻辑骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。
ConcreteClass实现父类所定义的一个或者多个抽象方法,每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。好了,基本情况就是这样的了。
模板方法分析
- 一般情况下都喜欢在抽象类声明最抽象最一般的事物属性方法,实现类实现具体事物的属性和方法,我却反其道而行之,因此在在复杂的项目中会对代码的阅读造成一定的影响。
优点:
- 封装不变的部分,扩展可变的部分。
- 提取了公共代码,便于维护。
- 行为由父类控制,子类实现。
模板方法之具体实现
Golang
Java
既然要实现,那就来个简单的栗子,想必你们都知道世上有两种生物,一种的具体活动就是“吃饭,睡觉,打豆豆。”(作者按:豆豆躺枪。)还有一种就是“吃饭,睡觉,敲代码。”(程序猿躺枪。)这个很简单,只需要一个动物的模型,也可能是其它物种,此处定义为动物。为了清楚认识我,先来个不是由模板方法实现的代码。首先来实现一下动物的代码:
public abstract class Animal{
//生物都需要吃东西
public abstract void eat();
//生物也都要睡觉
public abstract void sleep();
//其他活动
public abstract void otherthing();
//日常活动
public abstract void activities();
}
每种动物都要有吃东西、睡觉、娱乐活动、然后是一天的总结。但是每个物种的具体实现又不同,下面先给出“吃饭睡觉打豆豆”的具体实现。
public class AnimalY1 extends Animal{
public void eat(){
System.out.println("Y1动物吃糖葫芦和辣条"); //想到作者的都是出现幻觉的。
}
public void sleep(){
System.out.println("Y1动物睡在绳子上"); //想到小笼包的罚你在墙角面壁思过。
}
public void otherthing(){
System.out.println("打豆豆");
}
public void activities(){
this.eat();
this.otherthing();
this.sleep();
}
}
接下来就是第二个生物,程序猿的具体实现:
public class AnimalY2 extends Animal{
public void eat(){
System.out.println("吃外卖"); //好心酸有木有
}
public void sleep(){
System.out.println("睡在工位上"); //已泪目
}
public void otherthing(){
System.out.println("敲代码");
}
public void activities(){
this.eat();
this.otherthing();
this.sleep();
}
}
发现什么没有?没有?再仔细看看,是不是有一个activities每日总结都一样?对了,这个是共有的,自然要出现在抽象类中,尔等要记住一个原则:DRY。What,吾辈说错了?尔等说记得明明是DIY?可笑之极,Don’t take it for granted。吾辈的意思是:Don’t repeat yourself。如若在代码中发现多次重复,那么就需要想一想你的设计是不是有问题,如果不能说明原因,那就重构吧。下面我们做下修改,用上模板模式来做,首先修改一下抽象类:
public abstract class Animal{
//生物都需要吃东西
public abstract void eat();
//生物也都要睡觉
public abstract void sleep();
//其他活动
public abstract void otherthing();
//日常活动
public void activities(){
this.eat();
this.otherthing();
this.sleep();
}
}
在抽象的模板方法中定义了之后,把实现类的activies方法就可以移除了具体就不说了。测试类还需要否?那么简单的就不来了吧、、、好了,就到这里了
模板方法之使用场景
- 一次性实现一个算法的不变的部分,并将可变部分留给子类实现。
- 控制子类扩展。
- 各子类中公共行为可以被提取出来放到一个公共父类中。