二、模版模式与回调Template Method(行为型模式)
2016-04-15 15:52
411 查看
模版模式又叫模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情冴下,重新定义算法中的某些步骤。
我们使用冲泡咖啡和冲泡茶的例子
加工流程:
咖啡冲泡法:1.把水煮沸、2.用沸水冲泡咖啡、3.把咖啡倒进杯子、4.加糖和牛奶
茶冲泡法: 1.把水煮沸、2.用沸水冲泡茶叶、3.把 茶 倒进杯子、4.加蜂蜜
实践步骤:
1>创建一个模板(抽象)类:
Beverage(饮料)
2>创建一个咖啡类(Coffee)和茶(Tea)类,都继承Beverage抽象类
1.咖啡(Coffee)
2.茶(Tea)
运行结果:
-----------------------------------
煮开水
用水冲咖啡
倒进杯子
添加糖和牛奶
-----------------------------------
在模版模式中使用挂钩(hook)
存在一个空实现的方法,我们称这种方法为”hook”。子类可以视情况来决定是否要覆盖它。
1>我们对模板类(Beverage)进行修改
2>假如我们搞活动,喝一杯咖啡送一杯,修改咖啡(Coffee)类
3>使用上面的测试类
运行结果:
--------------------------------
煮开水
用水冲咖啡
倒进杯子
添加糖和牛奶
再来一杯
--------------------------------
结果中有“再来一杯”...
我们也可以这样使用挂钩,让其决定里面的代码是否执行
1>我们对模板类(Beverage)进行修改
2>我们对Coffee类进行修改,让其不添加配料
3>还是使用上面的测试类
运行结果:
------------------------------------------------------
煮开水
用水冲咖啡
倒进杯子
------------------------------------------------------
运行结果中没有添加配料
关于模板模式
1>模板模式定义了算法的步骤,把这些步骤的实现延迟到子类
2>模板模式为我们提供了一个代码复用的技巧
3>模板抽象类中可以定义具体方法、抽象方法和钩子方法
4>为了防止子类改变模板中的算法,可以将模板方法声明为final
5>钩子是一种方法,它在抽象类中不做事,或只做默认的事,子类可以选择要不要实现它
一.Java回调与模板方法模式
模板方法模式很常用,其目的是在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。在标准的模板方法模式实现中,主要是使用继承的方式,来让父类在运行期间可以调用到子类的方法。 其实在Java开发中,还有另外一个方法可以实现同样的功能,那就是Java回调技术,通过回调在接口中定义的方法,调用到具体的实现类中的 方法,其本质是利用Java的动态绑定技术,在这种实现中,可以不把实现类写成单独的类,而使用内部类或匿名内部类来实现回调方法。
二.回调方法应用举例
1.应用场景:
在实际业务中处理中,有这样一种场景,我们会在业务的开始设置线程上下文变量,在业务结束时对线程上下文变量进行清空,很类似于JDBC的操作后对数据库资源的释放,我们可以借助回调方法实现其执行步骤。
2.代码实现
(1)定义业务模板,process()方法就是算法步骤。
(2)回调处理类
(3)ContextHolder类
(4)测试类
三.两种实现方式的比较
1.模板方法模式借助于继承,对抽象方法在子类中进行扩展或实现,是在编译期间静态决定的,是类级关系。使用Java回调方法,利用动态绑定技术在运行期间动态决定的,是对象级的关系。
2.使用回调机制会更灵活,因为Java是单继承的,如果使用继承的方式,对于子类而言,今后就不能继承其它对象了。而使用回调,是基于接口的,方便扩展。 另外,如果有多个子类都要使用模板方法,则所有的子类都要实现模板方法,无形中增多了子类的个数。
3.使用模板方法模式使用继承方式会更简单点,因为父类提供了实现的方法,子类如果不想扩展,那就不用管。如果使用回调机制,回调的接口需要把所有可能被扩展的 方法都定义进去,这就导致实现的时候,不管你要不要扩展,你都要实现这个方法,哪怕你什么都不做,只是转调模板中已有的实现,都要写出来。
我们使用冲泡咖啡和冲泡茶的例子
加工流程:
咖啡冲泡法:1.把水煮沸、2.用沸水冲泡咖啡、3.把咖啡倒进杯子、4.加糖和牛奶
茶冲泡法: 1.把水煮沸、2.用沸水冲泡茶叶、3.把 茶 倒进杯子、4.加蜂蜜
实践步骤:
1>创建一个模板(抽象)类:
Beverage(饮料)
public abstract class Beverage { /** * 冲泡咖啡或茶...流程 */ public final void create(){ boilWater();//把水煮沸 brew();//用沸水冲泡... pourInCup();//把...倒进杯子 addCoundiments();//加... } public abstract void addCoundiments(); public abstract void brew(); public void boilWater() { System.out.println("煮开水"); } public void pourInCup() { System.out.println("倒进杯子"); } }
2>创建一个咖啡类(Coffee)和茶(Tea)类,都继承Beverage抽象类
1.咖啡(Coffee)
public class Coffee extends Beverage{ @Override public void addCoundiments() { System.out.println("添加糖和牛奶"); } @Override public void brew() { System.out.println("用水冲咖啡"); } }
2.茶(Tea)
public class Tea extends Beverage{ @Override public void addCoundiments() { System.out.println("添加蜂蜜"); } @Override public void brew() { System.out.println("用水冲茶"); } }
public class Test { public static void main(String[] args) { Coffee coffee = new Coffee(); coffee.create();//冲泡咖啡 //Tea tea = new Tea();//冲泡茶 //tea.create(); } }
运行结果:
-----------------------------------
煮开水
用水冲咖啡
倒进杯子
添加糖和牛奶
-----------------------------------
在模版模式中使用挂钩(hook)
存在一个空实现的方法,我们称这种方法为”hook”。子类可以视情况来决定是否要覆盖它。
1>我们对模板类(Beverage)进行修改
public abstract class Beverage { /** * 冲泡咖啡或茶...流程 */ public final void create(){ boilWater();//把水煮沸 brew();//用沸水冲泡... pourInCup();//把...倒进杯子 addCoundiments();//加... hook();//挂钩 } //空实现方法 public void hook(){} public abstract void addCoundiments(); public abstract void brew(); public void boilWater() { System.out.println("煮开水"); } public void pourInCup() { System.out.println("倒进杯子"); } }
2>假如我们搞活动,喝一杯咖啡送一杯,修改咖啡(Coffee)类
public class Coffee extends Beverage{ @Override public void addCoundiments() { System.out.println("添加糖和牛奶"); } @Override public void brew() { System.out.println("用水冲咖啡"); } /** * 挂钩 */ @Override public void hook() { System.out.println("再来一杯"); } }
3>使用上面的测试类
运行结果:
--------------------------------
煮开水
用水冲咖啡
倒进杯子
添加糖和牛奶
再来一杯
--------------------------------
结果中有“再来一杯”...
我们也可以这样使用挂钩,让其决定里面的代码是否执行
1>我们对模板类(Beverage)进行修改
public abstract class Beverage { /** * 冲泡咖啡或茶...流程 */ public final void create(){ boilWater();//把水煮沸 brew();//用沸水冲泡... pourInCup();//把...倒进杯子 //挂钩决定是否添加配料 if(hook()){ addCoundiments();//加... } //hook(); } /** * 默认添加配料 * @return */ public boolean hook() { return true; } //public void hook(){} public abstract void addCoundiments(); public abstract void brew(); public void boilWater() { System.out.println("煮开水"); } public void pourInCup() { System.out.println("倒进杯子"); } }
2>我们对Coffee类进行修改,让其不添加配料
public class Coffee extends Beverage{ @Override public void addCoundiments() { System.out.println("添加糖和牛奶"); } @Override public void brew() { System.out.println("用水冲咖啡"); } /** * 有的客人不喜欢加配料 */ @Override public boolean hook() { return false; } /*@Override public void hook() { System.out.println("再来一杯"); } */ }
3>还是使用上面的测试类
运行结果:
------------------------------------------------------
煮开水
用水冲咖啡
倒进杯子
------------------------------------------------------
运行结果中没有添加配料
关于模板模式
1>模板模式定义了算法的步骤,把这些步骤的实现延迟到子类
2>模板模式为我们提供了一个代码复用的技巧
3>模板抽象类中可以定义具体方法、抽象方法和钩子方法
4>为了防止子类改变模板中的算法,可以将模板方法声明为final
5>钩子是一种方法,它在抽象类中不做事,或只做默认的事,子类可以选择要不要实现它
一.Java回调与模板方法模式
模板方法模式很常用,其目的是在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。在标准的模板方法模式实现中,主要是使用继承的方式,来让父类在运行期间可以调用到子类的方法。 其实在Java开发中,还有另外一个方法可以实现同样的功能,那就是Java回调技术,通过回调在接口中定义的方法,调用到具体的实现类中的 方法,其本质是利用Java的动态绑定技术,在这种实现中,可以不把实现类写成单独的类,而使用内部类或匿名内部类来实现回调方法。
二.回调方法应用举例
1.应用场景:
在实际业务中处理中,有这样一种场景,我们会在业务的开始设置线程上下文变量,在业务结束时对线程上下文变量进行清空,很类似于JDBC的操作后对数据库资源的释放,我们可以借助回调方法实现其执行步骤。
2.代码实现
(1)定义业务模板,process()方法就是算法步骤。
public class BusinessTemplate<T> { private ProcessCallback<T> processCallback; public BusinessTemplate(ProcessCallback<T> callback) { this.processCallback = callback; } /** * 模板方法 */ public T process() { try { System.out.println(ContextHolder.getContext()); return processCallback.process(); } finally { ContextHolder.clear(); } } }
(2)回调处理类
public interface ProcessCallback<T> { /** * 回调处理。 * @return */ <span style="white-space:pre"> </span>T process(); }
(3)ContextHolder类
public class ContextHolder { private static final ThreadLocal<Context> threadLocal = new ThreadLocal<Context>(); public static void setContext(Context context) { threadLocal.set(context); } public static Context getContext() { return threadLocal.get(); } public static void clear() { threadLocal.remove(); } }
(4)测试类
public class TestCallBack { public static void main(String[] args) { Context context = new Context(); context.setBusinessName("name"); context.setBusinessType("type"); ContextHolder.setContext(context); BusinessTemplate<BusinessResult> template = new BusinessTemplate<BusinessResult>( new ProcessCallback<BusinessResult>() { public BusinessResult process() { BusinessResult businessResult = new BusinessResult(); return businessResult; } }); template.process(); System.out.print(ContextHolder.getContext()); } }
三.两种实现方式的比较
1.模板方法模式借助于继承,对抽象方法在子类中进行扩展或实现,是在编译期间静态决定的,是类级关系。使用Java回调方法,利用动态绑定技术在运行期间动态决定的,是对象级的关系。
2.使用回调机制会更灵活,因为Java是单继承的,如果使用继承的方式,对于子类而言,今后就不能继承其它对象了。而使用回调,是基于接口的,方便扩展。 另外,如果有多个子类都要使用模板方法,则所有的子类都要实现模板方法,无形中增多了子类的个数。
3.使用模板方法模式使用继承方式会更简单点,因为父类提供了实现的方法,子类如果不想扩展,那就不用管。如果使用回调机制,回调的接口需要把所有可能被扩展的 方法都定义进去,这就导致实现的时候,不管你要不要扩展,你都要实现这个方法,哪怕你什么都不做,只是转调模板中已有的实现,都要写出来。
相关文章推荐
- Android控件之ScrollView(滑动控件)探究
- 使用ZigBee模块实现PC机与树莓派的无线通信
- POJ-3252 Round Numbers
- android设计模式之Composite
- bzoj1070--写下一个傻逼错误,警示自己
- UVA_10245_ The Closest Pair Problem
- 在JS中如果函数名与变量名冲突,JS是怎么执行的?
- GET,POST,PUT,DELETE的区别
- 控件View动态设置高度时会卡顿、速度慢的情况解决
- Android 开发之使用Eclipse Debug调试详解(转)
- node authentication
- spring 4.0 不再支持ref local标签
- windows使用札记
- Yast: SSL certificate problem, verify that the CA cert is OK
- linux系统ps命令见解
- Oracle中给用户授予debug权限
- 断网后,看不到自己的牌,也不能操作,只能看到其他人出牌
- 2016年最新苹果开发者账号注册申请流程最强详解!
- volatile关键字和mutable关键字
- SQL-SELECT-检索数据(一)