模板方法模式定义了一个算法的步骤,并容许子类别为一个或多个步骤提供其实践方式。让子类别在不改变算法架构的状况下,从新定义算法中的某些步骤。(维基百科)java
定义中提到,模板方法定义了一个算法的步骤,容许子类为一个或者多个步骤提供其实践方式。也就说在这个模式中,算法的步骤是已经肯定的。可是不一样的子类中可能会有算法的步骤的具体实现。这样的话,就至关于父类中有算法的步骤,可是把具体的算法的步骤延迟到子类中去实现。这样就实现了算法的步骤和算法的步骤的具体实现分离。若是在有一种新的算法的实现,就再写一份子类就能够了。算法
模板方法模式的使用场景以下:若干个类有步骤相同的逻辑,可是步骤的实现方法不一样。复杂的算法,能够把核心算法设计为模板方法,具体的相关细节由子类去实现。举一个例子:Pascal君和java君在餐厅点完餐以后,想要吃饭。(不要问我为何Scala君不见了-_-)他们吃饭的步骤以下。准备餐具,吃饭,收拾餐具。可是Pascal君和java君准备的餐具不一样,吃饭的样子不同,而且Pascal君不喜欢收拾餐具。而java君每次吃饭后都要本身收拾餐具。设计模式
咱们分析二者的不一样处和共同的地方,相同的地方是,java君和Pascal君的吃饭的步骤,都是分三步,准备餐具,吃饭,收拾餐具,不一样的地方就是三个步骤的具体实现不一样,咱们尝试把相同的步骤提取出来,这些步骤就属于模板方法。咱们将其封装到父类中,这个父类能够是一个抽象类,而后让子类去继承父类,而后子类去具体实现具体的被模板调用的方法,这样就把变化的部分和不变的部分分离开了。架构
package template_method; /* * Created by 王镜鑫 on 2016/10/9 */ public abstract class Meal//抽象模板类 { protected abstract void prepareTableWare();//基本方法 准备餐具 protected abstract void eat();//基本方法 吃饭 protected abstract void clean();//基本方法 清理餐具 final public void start()//模板方法。调用基本方法,完成相关的逻辑 { prepareTableWare(); eat(); clean(); } } class JAVAMeal extends Meal//具体的java君吃饭 { protected void prepareTableWare()//实现java君特有的准备餐具 { System.out.println("I prepare a knives and forks!"); } protected void eat()//实现java君特有的吃 { System.out.println("I eat slowly!"); } protected void clean()//实现java君特有的清理 { System.out.println("I do cleaning"); } } class PascalMeal extends Meal//具体的Pascal君吃饭 { protected void prepareTableWare()//实现Pascal君特有的准备餐具 { System.out.println("I prepare a chopsticks!"); } protected void eat()//实现Pascal君特有的吃 { System.out.println("I eat quick!"); } protected void clean()//实现Pascal君特有的清理 { System.out.println("I do not do any cleaning"); } } class Work { public static void main(String[] args) { Meal javaMeal = new JAVAMeal(); javaMeal.start(); Meal pascalMeal = new PascalMeal(); pascalMeal.start(); } }
该代码的输出结果以下:ui
I prepare a knives and forks! I eat slowly! I do cleaning I prepare a chopsticks! I eat quick! I do not do any cleaning
这里有几点要注意的地方:咱们通常将父类的模板方法加上final关键字,防止被恶意覆盖,父类的抽象基本方法咱们通常用protected修饰符修饰,让其对除了子类和同包下的类可见。
咱们能够看到,模板方法模式十分简单,在平时的设计中应用也很是普遍。模板方法模式通常分红两部分,模板类和具体实现类。模板类中定义了具体的算法的实现步骤,和抽象的步骤的具体实现,而后子类继承抽象父类,而后去实现具体的步骤。模板方法模式封装了不变的部分,扩展了可变的部分。使用模板方法模式,能够很容易的扩展业务逻辑,若是Scala君也想要吃饭,咱们只要让他去继承Meal类。而后实现具体的准备餐具,进食,收拾餐具步骤便可。咱们根本不用修改原来已经存在的代码。符合对修改关闭,对扩展开放的设计原则。讲到这里,各位看官可能有疑问了。既然Pascal君吃饭不收拾桌子,咱们干脆不让他调用这个方法不就能够了。若是按照如今这个写法。咱们只能固定的调用这么多步骤,然而咱们在具体的项目中多是有些步骤能够省略的,好比Scala君喜欢用手抓着吃。那么他就不用准备餐具了。这样在调用准备餐具的方法,不是画蛇添足了吗?没错。的确有这样的问题,由于当前咱们的模板方法没法对子类进行行为约束,咱们的解决方案就是使用钩子方法。钩子方法的概念很简单。其实就是在父类中增长了is***的抽象方法,而后本身具体实现,返回true或者false代表是否须要调用这个方法。在父类的模板方法中先判断是否能够执行,而后在执行该步骤,这些个is***方法就是钩子方法,顾名思义,钩子能够钩取这些基本方法,控制其是否执行。钩子方法是一种很形象的叫法。
模板方法模式是一种很简单的设计模式。简单到咱们一直在用殊不知道。咱们将这种模式抽象出来,造成通常化的模式,而后取一个名字,在解决各类设计问题的时候,咱们一说这个名字,你们都懂,这就是规范的力量。举一个在平时用到模板方法模式的例子:servlet中的对一个请求进行具体的业务逻辑处理。是调用了Httpservlet中的service方法,而后service方法根据不一样的请求分发到具体的方法中,而具体的业务逻辑则由用户去继承HttpServlet类去实现,这就是一个常见的模板方法模式的应用。spa
本文转载自王镜鑫的我的博客 » 【原创】设计模式系列(二)——模板方法模式设计