Template mode

Recently, ofo small yellow car announced to enter Paris, France, officially entering the 20th country in the world. Shared bicycles have already changed the way we travel. Take myself as an example. Whenever I get off the subway, the first thing I do is to lock a shared bicycle at the speed of light, and the speed of 100-meter sprint grabs it before others.

And everyone is repeating the same action, taking out the phone to unlock, ride the bike, lock, settle, wow ~ what a spectacular scene, and even some people ride the car away without unlocking, the lock is broken.


Why use the template method pattern

Now shared bicycles are divided into unlocking methods. Generally, there are two types of scanning code unlocking and password unlocking. Let's look at the realization of the shared bicycle usage process.

The normal thinking logic is to abstract a parent class, and the child class inherits the parent class and implements the parent class method. OK, look at the abstract class code:

publicabstractclassAbstractClass{// Unlock publicabstractvoidunlock();// Ride publicabstractvoidride();// Lock publicabstractvoidlock();// Settle publicabstractvoidpay();// User uses publicabstractvoiduse();}

The abstract class defines several basic processes for us to use shared bicycles. Now there are two different ways to unlock the bicycles, both of which inherit the abstract class. The code is as follows:

// publicclassScanBicycleextendsAbstractClass{@Overridepublicvoidunlock(){ System.out.println("Scan code to unlock"); }@Overridepublicvoidride(){ System.out.println("It's cool to ride"); }@Overridepublicvoidlock(){ System .out.println("lock"); }@Overridepublicvoidpay(){ System.out.println("settlement"); }@Overridepublicvoiduse(){ unlock(); ride(); lock(); pay(); }}

The above is to unlock and ride by scanning the code, and then look at the password unlocking and riding, the code is as follows:

publicclassCodeBicycleextendsAbstractClass{@Overridepublicvoidunlock(){ System.out.println("Password to unlock"); }@Overridepublicvoidride(){ System.out.println("Ride is cool"); }@Overridepublicvoidlock(){ System.out. println("lock"); }@Overridepublicvoidpay(){ System.out.println("settlement"); }@Overridepublicvoiduse(){ unlock(); ride(); lock(); pay(); }}

Well, both methods are defined, look at the client's call:

publicclassClient{publicstaticvoidmain(String[] args){        ScanBicycle scanBicycle =newScanBicycle();        scanBicycle.use();        System.out.println("========================");        CodeBicycle codeBicycle =newCodeBicycle();        codeBicycle.use();    }}

The result is as follows:

Scan code to unlock

It's cool to ride

locked

settlement

========================

Scan code to unlock

It's cool to ride

locked

settlement

I believe that you have already seen the problem of the code. The implementation of the use method is the same, that is, the code is repeated. This is a disease that must be cured. The prescription is the template mode.

Template method pattern

definition

定义抽象类并且声明一些抽象基本方法供子类实现不同逻辑,同时在抽象类中定义具体方法把抽象基本方法封装起来,这就是模板方法模式。

UML


模板方法模式

模板方法模式涉及到的角色有两个角色:

- 抽象模板角色:定义一组基本方法供子类实现,定义并实现组合了基本方法的模板方法。

- 具体模板角色:实现抽象模板角色定义的基本方法

模板方法模式还涉及到以下方法的概念:

基本方法

抽象方法:由抽象模板角色声明,abstract修饰,具体模板角色实现。

钩子方法:由抽象模板角色声明并实现,具体模板角色可实现加以扩展。

具体方法:由抽象模板角色声明并实现,而子类并不实现。

模板方法

抽象模板角色声明并实现,负责对基本方法的调度,一般以final修饰,不允许具体模板角色重写。模板方法一般也是一个具体方法。

模式实战

利用模板方式模式对上面的代码进行重构,来看抽象模板角色,代码如下:

publicabstractclassAbstractClass{protectedbooleanisNeedUnlock =true;// 默认需要开锁/**

    * 基本方法,子类需要实现

    */protectedabstractvoidunlock();/**

    * 基本方法,子类需要实现

    */protectedabstractvoidride();/**    * 钩子方法,子类可实现    *    *@paramisNeedUnlock    */protectedvoidisNeedUnlock(booleanisNeedUnlock){this.isNeedUnlock = isNeedUnlock;    }/**

    * 模板方法,负责调度基本方法,子类不可实现

    */publicfinalvoiduse(){if(isNeedUnlock) {            unlock();        }else{            System.out.println("========锁坏了,不用解锁========");        }        ride();    }}

抽象模板角色定义了unlock和ride两个使用单车的基本方法,还有一个钩子方法,用来控制模板方法逻辑顺序,核心是use模板方法,用final修饰,该方法完成对基本方法调度。注意,模板方法中对基本方法的调度是有顺序有规则的。还有一点,基本方法都是protected修饰的,因为基本方法都是在以public修饰的模板方法中调用,并且可以由子类实现,并不需要暴露给其他类调用。

现在来看两个具体模板角色的实现:

// 扫码开锁的单车publicclassScanBicycleextendsAbstractClass{@Overrideprotectedvoidunlock(){        System.out.println("========"+"扫码开锁"+"========");    }@Overrideprotectedvoidride(){        System.out.println(getClass().getSimpleName() +"骑起来很拉风");    }protectedvoidisNeedUnlock(booleanisNeedUnlock){this.isNeedUnlock = isNeedUnlock;    }}// 密码开锁的单车publicclassCodeBicycleextendsAbstractClass{@Overrideprotectedvoidunlock(){        System.out.println("========"+"密码开锁"+"========");    }@Overrideprotectedvoidride(){        System.out.println(getClass().getSimpleName() +"骑起来很拉风");    }protectedvoidisNeedUnlock(booleanisNeedUnlock){this.isNeedUnlock = isNeedUnlock;    }}

可以看到,相比之前的实现,现在两个具体类都不需要实现use方法,只负责实现基本方法的逻辑,职责上变得更加清晰了。来看用户如何使用:

publicclassClient{publicstaticvoidmain(String[] args){        ScanBicycle scanBicycle =newScanBicycle();        scanBicycle.use();                CodeBicycle codeBicycle =newCodeBicycle();        codeBicycle.use();    }}

运行结果如下:

========扫码开锁========

ScanBicycle骑起来很拉风

========密码开锁========

CodeBicycle骑起来很拉风

当我以百米冲刺的速度跑到共享单车面前时,发现这辆车的锁是坏掉的,也就是不用开锁,免费的,骑回家收藏也没问题。在代码中只要调用钩子方法isNeedUnlock就好,实现如下:

publicclassClient{publicstaticvoidmain(String[] args){        ScanBicycle scanBicycle =newScanBicycle();        scanBicycle.isNeedUnlock(false);        scanBicycle.use();        CodeBicycle codeBicycle =newCodeBicycle();        codeBicycle.isNeedUnlock(true);        codeBicycle.use();    }}

运行结果如下:

========锁坏了,不用解锁========

ScanBicycle骑起来很拉风

========密码开锁========

CodeBicycle骑起来很拉风

上面提到模板方法对基本方法的调度是有顺序的,也就是说模板方法中的逻辑是不可变的,子类只实现可以被实现的基本方法,但不会改变模板方法中的顶级逻辑。而钩子方法的使用只是对模板方法中逻辑的控制,影响的是模板方法的结果,并不会改变原有逻辑。

模板方法模式的优缺点

优点

1)良好的封装性。把公有的不变的方法封装在父类,而子类负责实现具体逻辑。

2)良好的扩展性:增加功能由子类实现基本方法扩展,符合单一职责原则和开闭原则。

3)复用代码。

缺点

1)由于是通过继承实现代码复用来改变算法,灵活度会降低。

2)子类的执行影响父类的结果,增加代码阅读难度。

总结

模板方法模式看上去简单,但是整个模式涉及到的都是面向对象设计的核心,比如继承封装,基于继承的代码复用,方法的实现等等。当中还有涉及到一些关键词的使用,也是我们Java编程中需要掌握的基础。总体来说,模板方法模式是很好的学习对象。下一篇是中介者模式,您的点赞和关注是我的动力,再会!

作者:Jet啟思

链接:https://www.jianshu.com/p/a25dadafad1b

來源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325640300&siteId=291194637