作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
阶段4、深入jdk其余源码解析
阶段5、深入jvm源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】
码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。
(引用GoF 设计模式)
模板方法模型 是一种行为设计模型。 模板方法 是一个定义在父类别的方法,在 模板方法 中会呼叫多个定义在父类别的其他方法,而这些方法有可能只是抽象方法并没有实作, 模板方法 仅决定这些抽象方法的执行顺序,这些抽象方法的实作由子类别负责,并且子类别不允许覆写模板方法。
(引用维基百科)
package template;
/**
* 抽象类: 作为基类,其子类必须实现抽象方法
*/
public abstract class CaffeineBeverage {
/**
* 整个流程处理
* 声明为final以免子类改变这个算法的顺序
*/
final void prepareRecipe() {
// 把水煮沸
boilWater();
// 用热水泡咖啡或茶
brew();
// 把饮料倒进杯子
pourInCup();
// 在饮料内加入适当的调料
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("boil water. Both.");
}
void pourInCup() {
System.out.println("pour in cup. Both");
}
}
public class Coffee extends CaffeineBeverage{
@Override
void brew() {
System.out.println("Coffee brew.");
}
@Override
void addCondiments() {
System.out.println("Coffee add sugar and milk.");
}
}
public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Tea brew.");
}
@Override
void addCondiments() {
System.out.println("Tea add lemon.");
}
}
public interface ICallback {
void methodToCallback();
}
public class BClass {
public void process(ICallback callback) {
callback.methodToCallback();
}
}
/**
* 1.回调跟模板模式一样,也具有复用和扩展的功能.
* 2.回调分为同步回调、异步回调(延迟回调)。
* 同步回调指在函数返回之前执行回调函数、异步回调指的是在函数返回之后执行回调函数。
* 3.从应用场景看,同步模式看起来更像模式模式,异步回调看起来更像观察者模式。
*/
public class AClass {
public static void main(String[] args) {
BClass b = new BClass();
b.process(new ICallback() {
@Override
public void methodToCallback() {
System.out.println("method call back.");
}
});
}
}
回调跟模板模式一样,也具有复用和扩展的功能。A
类可以根据实际情况自定义实现回调方法。有具大的操作空间。
相对于普通的函数调用来说,回调是一种双向调用关系。A类事先注册某个函数F到B类,A类在调用B类的P函数的时候,B类反过来调用A类注册给它的F函数。即A调用B,B返过来调用A
。
应用举例:
模块模式VS回调
从应用场景上来看,同步回调跟模板模式几乎一致。它们都是在一个大的算法骨架中,自由替换其中的某个步骤,起到代码复用和扩展的目的。而异步回调跟模板模式有较大差别,更像是观察者模式。
从代码实现上来看,回调和模板模式完全不同。回调基于组合关系来实现,把一个对象传递给另一个对象,是一种对象之间的关系;模板模式基于继承关系来实现,子类重写父类的抽象方法,是一种类之间的关系。
组合优于继承。实际上,这里也不例外。在代码实现上,回调相对于模板模式会更加灵活,主要体现在下面几点。
模板模式主要用来解决复用
和扩展
问题。
复用
把一个算法中不变的流程抽象到父类的模板方法 templateMethod()
中,将可变的部分method1()、method2()
留给子类 ContreteClass1
和 ContreteClass2
来实现。
InputStream、OutputStream、Reader、Writer
。在InputStream
中,read()
函数是一个模板方法,该方法定义了读取数据的整个流程,并且暴露了一个可以由子类定制的抽象方法。addAll()
函数可以看作模板方法,虽然并未定义abstract
抽象方法,但是函数直接抛出了异常。若要使用该方法,必须重写。扩展
HttpServlet
的 service()
方法就是一个模板方法,它实现了整个 HTTP 请求的执行流程,doGet()、doPost()
是模板中可以由子类来定制的部分。实际上,这就相当于Servlet
框架提供了一个扩展点(doGet()、doPost()
方法),让框架用户在不用修改Servlet
框架源码的情况下,将业务代码通过扩展点镶嵌到框架中执行。
又比如compareTo
方法。让子类扩展该方法的实现。
模块模式基于继承。对Java
单继承语言来说,会有较大限制。