当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 结合JDK源码看设计模式——模板方法模式

结合JDK源码看设计模式——模板方法模式

2019年04月11日  | 移动技术网IT编程  | 我要评论

前言:

  相信很多人都听过一个问题:把大象关进冰箱门,需要几步?

  第一,把冰箱门打开;第二,把大象放进去;第三,把冰箱门关上。我们可以看见,这个问题的答案回答的很有步骤。接下来我们介绍一种设计模式——模板方法模式,你会发现,它与这个问题的答案实际上有很多共同之处。

一、定义

  定义一个算法骨架,允许子类为一个或多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。

二、适用场景

  一次性实现一个算法的不变的部分,将可变的行为留给子类实现

  也就是将各子类中公共行为被提取出来并集中到一个公共父类中,从而避免代码重复。还是拿上面大象放进冰箱里面的例子,打开冰箱和关上冰箱都是不变的行为,我们可以将其放在公共父类实现。但是放大象,怎么放?是先放背对着冰箱放,还是面对着冰箱放。不想放大象,放老虎或者其他动物呢?这些就是我们可变的行为,这个就放入子类中实现。可以说,模板方法提供了一个很好的代码复用平台

三、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的模板。

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网