结合JDK源码看设计模式——模板方法模式
前言:
相信很多人都听过一个问题:把大象关进冰箱门,需要几步?
第一,把冰箱门打开;第二,把大象放进去;第三,把冰箱门关上。我们可以看见,这个问题的答案回答的很有步骤。接下来我们介绍一种设计模式——模板方法模式,你会发现,它与这个问题的答案实际上有很多共同之处。
一、定义
定义一个算法骨架,允许子类为一个或多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
二、适用场景
一次性实现一个算法的不变的部分,将可变的行为留给子类实现
也就是将各子类中公共行为被提取出来并集中到一个公共父类中,从而避免代码重复。还是拿上面大象放进冰箱里面的例子,打开冰箱和关上冰箱都是不变的行为,我们可以将其放在公共父类实现。但是放大象,怎么放?是先放背对着冰箱放,还是面对着冰箱放。不想放大象,放老虎或者其他动物呢?这些就是我们可变的行为,这个就放入子类中实现。可以说,模板方法提供了一个很好的代码复用平台
三、JDK中的模板方法模式
在刚接触ArrayList的时候一直没注意它继承的类和实现的接口。直到现在讲到了模板方法模式,再去看ArrayList的时候能明白不少。在前面的博客中有提到List接口和Cloneable接口是用来实现什么设计模式的。今天就来看看这个ArrayList的父类AbstractList。
AbstractList就是我们前面适用场景中介绍的父类(也叫模板类),这个类里面即提供了公共的方法(不可供子类修改),又提供了可让子类修改的方法。下面我们直接看源码,由于方法很多,我们就介绍一下addAll方法。
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
add(index++, e);
modified = true;
}
return modified;
}
}
上面的是AbstractList的addAll方法,可以看见这个方法没有限定子类是否去修改,子类由需要就去修改,如果子类不想修改,完全能够按照AbstractList中的逻辑添加元素。事实上我看了一遍AbstractList中的方法发现除了一些私有的方法不能给子类给子类访问之外,其余的基本上都是可以给子类去选择是否修改的。如果子类觉得父类的方法可行,那么直接使用父类的方法即可。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index); Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved); System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
}
上面这个就是ArrayList中的addAll方法。
但是AbstractList里面有一个方法,就是get()方法,AbstractList明确要求要让子类实现。由于代码较少,我就直接截图
左边是父类AbstractList中的,右边是ArrayList中的方法。在父类中没有直接写出实现代码,而是让子类自己手动去实现。除此之外其实还有一个方法就是AbstractList父类AbstractCollection中的toString方法。在ArrayList中是没有的,但是平常在写代码时候,是可以直接调用的,这就是一个公共的方法。
四、总结
模板方法模式只需要简单的继承关系就可以完成。相信平常我们在写代码的时候也是使用过模板方法模式,只是我们并不知道是这种设计模式。这里多说一下,如果我们希望子类不要修改父类的方法,只需要加上final修饰即可;如果希望子类一定重写父类的方法,就将父类的方法用abstract修饰;如果子类可以修改也可以不修改,就可以像addAll方法那样设计即可。重点理解模板,这个模板尽量使用抽象类。因为抽象类比接口更加的灵活,能将模板定义的更好。其实看完上面的源码解析,总结起来就是一句话AbstractList是ArrayList的模板。
结合JDK源码看设计模式——模板方法模式的更多相关文章
- 结合JDK源码看设计模式——桥接模式
前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...
- 结合JDK源码看设计模式——原型模式
定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...
- 结合JDK源码看设计模式——迭代器模式
前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...
- 结合JDK源码看设计模式——建造者模式
概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...
- 结合JDK源码看设计模式——策略模式
前言: 现在电商已经成为我们生活中不可或缺的购物渠道,同时各大商家会针对不同的时间做出不同的折扣,这在我们看来就是一种营销手段,也是一种策略,今天我们就来讲讲JDK中的策略模式是怎么样的. 一.定义 ...
- 结合JDK源码看设计模式——组合模式
前言: 相信大家都打开过层级很多很多的文件夹.如果把第一个文件夹看作是树的根节点的话,下面的子文件夹就可以看作一个子节点.不过最终我们寻找的还是文件夹中的文件,文件可以看做是叶子节点.下面我们介绍一种 ...
- 结合JDK源码看设计模式——单例模式
定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...
- 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂
三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...
- 结合JDK源码看设计模式——享元模式
前言 在说享元模式之前,你一定见到过这样的面试题 public class Test { public static void main(String[] args) { Integer a=Inte ...
随机推荐
- PAT1079 :Total Sales of Supply Chain
1079. Total Sales of Supply Chain (25) 时间限制 250 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHE ...
- linux Tcpdump使用方法
用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的&qu ...
- Unity文档阅读 第二章 依赖注入
Introduction 介绍Chapter 1 outlines how you can address some of the most common requirements in enterp ...
- CentOS下使用命令行Web浏览器Links
前言: Links是一个运行在命令行模式下的Web浏览器,只能查看字符.Links的官网是Click here. 安装Links yum install links 使用Links links URL ...
- Step by step guide to set up master and slave machines on Windows
Note: There is no need to install Jenkins on the slave machine. On your master machine go to Manage ...
- navicat for mysql 破解方法
https://www.cnblogs.com/da19951208/p/6403607.html 破解教程
- 关于maven的配置使用 这一篇还比较全 2017.12.13
https://www.cnblogs.com/tangshengwei/p/6341462.html
- 译MassTransit 消息契约
消息契约 在MassTransit中,使用.NET .NET系统定义消息契约.消息可以使用类和接口来定义,但是,建议类型使用只读属性而不使用行为. 注意:强烈建议使用消息接口的接口,基于多年的经验,具 ...
- attr和prop的区别以及在企业开发中应该如何抉择
attr和prop有很多相同的地方,比如都可以操作标签的属性节点,而且获取的时候都只可以获取到相同节点的第一个,例如这样: $('span').attr('class');和$('span').pro ...
- 关于bash
Linux中有一位名叫"巴士"的tool.他是如何出世的呢?原来,他是一个为GNU计划(GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起 ...