template method模式:将部分的特殊实现交给子类
场景:
(1) 我们有多种优惠策略
(2) 不同的优惠策略在计算价格的时候,有一些是通用的基础逻辑
(3) 然后,每种优惠策略 还有一些是自己 比较特殊的价格计算的逻辑
不用模板方法的代码实现:
我们比如说,有3中优惠的方式,
第一种折扣计算器类DiscountCalculator1,里面有方法calculate,方法实现 有一个通用的计算逻辑,还有优惠计算器1的特殊计算逻辑;
分别还有,
第二种折扣计算器类DiscountCalculator2,里面有方法calculate,方法实现 有一个通用的计算逻辑,还有优惠计算器2的特殊计算逻辑;
第二种折扣计算器类DiscountCalculator3,里面有方法calculate,方法实现 有一个通用的计算逻辑,还有优惠计算器3的特殊计算逻辑;
然后,我们在main方法中去调用它们,
public static void main(String[] args) { DiscountCalculator1 calculator1 = new DiscountCalculator1(); calculator1.calculate(); DiscountCalculator2 calculator2 = new DiscountCalculator2(); calculator2.calculate(); DiscountCalculator3 calculator3 = new DiscountCalculator3(); calculator3.calculate(); }
输出如下:
通用的计算逻辑
优惠计算器1的特殊计算逻辑
通用的计算逻辑
优惠计算器2的特殊计算逻辑
通用的计算逻辑
优惠计算器3的特殊计算逻辑
Process finished with exit code 0
那么这里,如果不用设计模式的话,有一个问题,就是说 这个三种优惠方式计算器里面,都有一段通用计算逻辑,其实是完全相同的代码,但是完全相同的一段代码,给通过复制粘贴的方式,放到了不同的类里去,那么一旦说,那个通用的计算的计算逻辑 要修改,就涉及到多个类都要去修改那个代码,如果你一旦忘了修改某个类中的那段代码,后果不堪设想;而且到了后期,几乎没人记得清楚,那段通用逻辑代码放在了多少个类中,如果要排查,需要将很多类重新读一遍代码,这就是垃圾代码,扩展性,维护性,很烂。所以这个情况下,我们必须要用设计模式。
使用模板方法的代码实现:
这个时候,我们要这么来玩,
我们先定义一个接口DiscountCalculator,这个接口中定义了一个方法void calculate()即可。当然,这个接口肯定是要定义的,因为我们要面向接口去开发的嘛!
然后,定义一个抽象类作为基础类AbstractDiscountCalculator implement DiscountCalculator,
在抽象的基础类中,定义一个方法private void commonCalculate(),其中封装了一段通用的计算逻辑;
还有一个protected abstract void specificCalculate();,这个是没有实现的,因为它是一个抽象方法;
最后,还要重写接口中的对外提供的调用方法public void calculate(),其中,先执行commonCalculate()这段通用的计算逻辑,再执行特殊的计算逻辑specificCalculate();
那么,在具体的实现类中,比如DiscountCalculator1 extends AbstractDiscountCalculator,我们只需实现父类中抽象方法speificCalculate()的具体实现逻辑,优惠计算器1的特殊计算逻辑即可。
代码如下:
public class TemplateMethodPatternDemo { public static void main(String[] args) { DiscountCalculator calculator1 = new DiscountCalculator1(); calculator1.calculate(); DiscountCalculator calculator2 = new DiscountCalculator2(); calculator2.calculate(); DiscountCalculator calculator3 = new DiscountCalculator3(); calculator3.calculate(); } public interface DiscountCalculator { void calculate(); } /** * 模板方法实现的精华所在 */ public static abstract class AbstractDiscountCalculator implements DiscountCalculator { public void calculate(){ // 完成通用的计算逻辑 commonCalculate(); // 完成特殊的计算逻辑 specificCalculate(); } private void commonCalculate(){ System.out.println("通用的计算逻辑"); } protected abstract void specificCalculate(); } public static class DiscountCalculator1 extends AbstractDiscountCalculator{ public void specificCalculate(){ System.out.println("优惠计算器1的特殊计算逻辑"); } } public static class DiscountCalculator2 extends AbstractDiscountCalculator{ public void specificCalculate(){ System.out.println("优惠计算器2的特殊计算逻辑"); } } public static class DiscountCalculator3 extends AbstractDiscountCalculator{ public void specificCalculate(){ System.out.println("优惠计算器3的特殊计算逻辑"); } } }
在这里面的很好的设计就是,通用的计算逻辑,全部给抽出来放在抽象父类AbstractDiscountcalculator中的commonCalculate()方法这个地方,然后,特殊的计算逻辑,定义成抽象方法specificCalculate(),父类不实现,交给子类,比如DiscountCalculator1 extends AbstractDiscountCalculator,子类继承父类之后,子类里面去覆盖实现父类中的这个特殊的计算逻辑。这样的话,对于不同策略优惠的计算器来说,它们通用的计算逻辑没有重复在各个具体的实现中,而是抽取到抽象的父类里面去了,只有这么一块;然后每个子类里面分别去实现自己自己特殊的计算逻辑即可。而这个时候,我们如果要把通用的计算逻辑修改一下,只需要在抽象的父类这一个类里面修改就可以了,也就是说,模板方法这个模式,就是把多个类里面 通用的逻辑 抽象到一个抽象父类里面去,然后,再在各个子类里面去实现它们特有的一个逻辑,在抽象父类里面,对外提供的方法,会定义清楚什么时候去执行通用的计算逻辑,什么时候去执行这个特殊的计算逻辑,特殊的计算逻辑这个方法,是给定义成抽象方法,留给子类去覆盖的,这样就通过模板方法模式,定义一个抽象方法,完美解决了重复性代码的问题。
总结:
模板方法设计模式,这个应该是,最高频使用的设计模式,这个高频到了,我都不用在这里举个什么例子,因为在任何一个系统中,一定会出现说,多个类中,其实都有相同的代码,此时就可以使用模板方法设计模式,然后将多个类中通用的设计模式,抽取到一个父类中去。那么什么叫做模板方法呢,其实就是父类里面定义成抽象方法,就是所谓的模板方法,因为这个需要子类去具体实现抽象的方法,只是一个模板,它并没有实现,模板的实现是通过子类去实现的。