前言
📣 📣 📣 📢📢📢
☀️☀️点开就是缘分认识一下,我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。
📒 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️,擅长使用Java技术开发web项目和工具
📒 文章内容丰富:覆盖大部分java必学技术栈,前端,计算机基础,容器等方面的文章
📒 如果你也对Java感兴趣,关注小冷吧,一起探索Java技术的生态与进步,一起讨论Java技术的使用与学习
✏️高质量技术专栏专栏链接: 微服务,数据结构,netty,单点登录,SSM ,SpringCloudAlibaba等
😝公众号😝 : 想全栈的小冷,分享一些技术上的文章,以及解决问题的经验
⏩当前专栏:设计模式系列
⏩专栏代码地址: 代码地址
模板方法模式 Teamplate Method
什么是模板? 可以理解为有镂空的塑料板,我们可以用笔去透过模板的镂空汇出整齐的字 ,
了解模板方法模式
我们这次要实现的模板方法模式是带有模板功能的模式,组成模板的方法被定义在父类中,由于这些方法是抽象方法,只查看父类的代码实无法知道这些方法最后进行何种具体的处理。唯一可以知道的是父类如何调用这些方法的
实现上述这些抽象方的是子类,在子类中实现了抽象方法也就决定了具体的处理,不同的子类实现不同的具体处理,当父类模板方法被调用的时候程序执行的行为也会出现不同也就是说:
- 父类定义方法和流程
- 子类完成具体方法的实现
示例程序
类表
类图
AbstractDisplay类定义了 四个方法 其中display方法 依次调用了 open print close 三个方法,这三个方法虽然在AbstractDisplay中已经声明,但是没有实际上的实现,这个调用抽象方法的display方法就是模板方法
抽象模板类
AbstaractDisplay
作为模板类(父类)它定义了需要实现的抽象方法和执行流程
public abstract class AbstaractDisplay {
//子类实现
public abstract void open();
public abstract void print();
public abstract void close();
//执行流程
public final void display(){
open();
for (int i = 0; i <5 ; i++) {
print();
}
close();
}
}
子类 CharDisplay
作为子类 继承模板类并且重写方法
public class CharDisplay extends AbstaractDisplay {
//需要显示的字符
private char ch;
public CharDisplay(char ch) {
this.ch = ch;
}
//重写父类方法
@Override
public void open() {
System.out.print("<<");
}
@Override
public void print() {
System.out.print(ch);
}
@Override
public void close() {
System.out.println(">>");
}
}
子类 StringDisplay
使用字符串来输出内容,并且用printline来改变格式
public class StringDisplay extends AbstaractDisplay {
private String string;
private int width;
public StringDisplay(String string) {
this.string = string;
this.width = string.getBytes().length;
}
//实现父类方法
@Override
public void open() {
printline();
}
@Override
public void print() {
System.out.println("|" + string + "|");
}
@Override
public void close() {
printline();
}
private void printline() {
System.out.print("+");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("+");
}
}
示例测试
public class test {
public static void main(String[] args) {
AbstaractDisplay charDisplay = new CharDisplay('H');
AbstaractDisplay stringDisplay = new StringDisplay("hello word");
AbstaractDisplay stringDisplay1 = new StringDisplay("你好世界");
charDisplay.display();
stringDisplay.display();
stringDisplay1.display();
}
}
模板方法中的角色
- 抽象类 不仅定义模板方法display 还负责声明方法中所需要的抽象方法
- 具体类 重写抽象类中定义的抽象方法,来达到调用不同子类实现走统一流程但是不同效果的目的
拓展思路
模板方法给我们带来的什么好处呢? 他的优点是什么? 其实在示例过程中就已经很明显了
流程是定义在父类中的, 假如父类的模板方法里加入了算法,子类也无需去关心。
假如我们没有模板方法 那么就会编写许多个实现类每个类都有自己的display,万一某个类的display出了什么问题 编写完如果没有bug还好 要是一段时间之后,我们发现有bug 该如何,我们就必须将使用这个模板类所有的地方修改才能解决,如果使用了模板方法 只需要修改抽象类中的模板方法就可以了
在实例中 我们用final来修饰模板方法表示子类无法重写这个方法 也就不会影响到父类模板方法的执行
父类子类的协作性
在上面的示例就可以看出来 不管是char的实现还是stirng的实现模板方法的 父子类工作室紧密相连的,在不知道父类模板方法的情况下想要实现子类是很困难的事情
父子类的一致性
在示例程序中 不管是子类有多少,都是保存在抽象类的类型变量中在调用模板方法,父类变量保存子类的优点就是不管是保存到哪个子类的示例,程序都可以正常工作,折中原则被称为里氏替代原则
父类对子类的要求
在我们理解的类层次中,往往都是从子类来进行思考的
- 子类中可以使用父类的方法
- 可以通过子类增加方法来实现新的功能
- 在子类重写父类方法可以改变程序行为
现在我们改变一下日常 站在父类的角度进行思考,在父类中 我们声明了抽象方法,将该方法的实现任务交给了子类,就程序而言声明抽象方法是希望达到一些目的: 要求子类去时间抽象方法
这种方式被称为子类这人
父类子类之间的写作
模板方法模式 是父子类一起支撑一个程序,通过让父类少一些实现 让子类多一些实现的方式来增强了子类的灵活性 同时有模板方法的存在划分了父子类的任务需求 父类负责定义方法和流程 子类负责具体方法实现,不过如何划分 是由我们开发者来决定 这些需要我们根据经验来决定
拓展示例
去哪里可以看到模板方法呢 ?
在java.io的inputstream中就可以看到对模板方法的使用