设计之美——模板方法模式

一、什么是模板方法模式

  概念:定义一个操作中的算法的骨架,而将一字儿步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

  通俗的讲,模板方法模式是通过把不变行为搬到超类,去除子类里面的重复代码提现它的优势,它提供了一个很好的代码复用平台。当不可变和可变的方法在子类中混合在一起的时候,不变的方法就会在子类中多次出现,这样如果摸个方法需要修改则需要修改很多个,虽然这个这个问题在设计之初就应该想好。这个时候模板方法模式就起到了作用了,通过模板方法模式把这些重复出现的方法搬到单一的地方,这样就可以帮助子类摆脱重复不变的纠缠。

  举个好懂的例子,小时候笔者家里穷,在农村上小学的时候考试都是每个学生手抄试卷,因为那个时候学校还没有试卷印刷。全班五十多个学生每个学生都要重复抄一遍黑板的试卷,并且像笔者这样的近视眼很容易就抄错了,8抄成3,7抄成1等到,然后明明做对了但是分数就是不高,导致笔者一直是全班倒数。这就是个很严重的重复不可变的问题,现在条件好了不少,学生不需要抄试卷,试卷印刷就解决了这个重复抄试卷的问题。模板方法也是类似。

二、模式对比

1、抄试卷模式

笔者就以抄试卷模式为名来阐述重复不变带来的不便,下面会对该模式进行改进。

学生甲抄的试卷

public class TestPaperA {
    //试卷第一题
    public void testQuestion1(){
        System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈  B.大姨妈  C.姑妈  D.舅妈");
        System.out.println("答案:C");
    }

    //试卷第二题
    public void testQuestion2(){
        System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");
        System.out.println("答案:C");
    }

    //试卷第三题
    public void testQuestion3(){
        System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");
        System.out.println("答案:B");
    }
}

学生乙抄的试卷

public class TestPaperB {
    //试卷第一题
    public void testQuestion1(){
        System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈  B.大姨妈  C.姑妈  D.舅妈");
        System.out.println("答案:A");
    }

    //试卷第二题
    public void testQuestion2(){
        System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");
        System.out.println("答案:C");
    }

    //试卷第三题
    public void testQuestion3(){
        System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");
        System.out.println("答案:D");
    }
}

客户端代码

public class ShowAnswer {

    public static void main(String[] args) {
        System.out.println("学生甲的试卷");
        TestPaperA stuA = new TestPaperA();
        stuA.testQuestion1();
        stuA.testQuestion2();
        stuA.testQuestion3();
        System.out.println("学生乙的试卷");
        TestPaperB stuB = new TestPaperB();
        stuB.testQuestion1();
        stuB.testQuestion2();
        stuB.testQuestion3();
    }

}

很容易发现上面两个学生抄的试卷有很多重复的地方,比如试卷的题目,输出答案的方法,这些都在每个学生试卷类中混合在一起了,既不利于维护,也不利于浏览,下面看一下模板方法模式是怎么改进的。

2、模板方法模式

将每个学生试卷的重复部分提取出来,题目,作答等等。

首先改造试卷类,将该类改为抽象类,在该类中我添加了三个抽象的方法用于子类实现,学生都是要作答的,但是答案不一样,所以可以将作答的过程作为重复不变的方法提取出来,代码如下。

public abstract class TestPaper {
    //试卷第一题
    public void testQuestion1(){
        System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈  B.大姨妈  C.姑妈  D.舅妈");
        System.out.println("答案:" + answer1());
    }

    //试卷第二题
    public void testQuestion2(){
        System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");
        System.out.println("答案:" + answer2());
    }

    //试卷第三题
    public void testQuestion3(){
        System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");
        System.out.println("答案:" + answer3());
    }

    //这三个钩子方法是给每个子类去实现,并返回答案的
    public abstract String answer1();
    public abstract String answer2();
    public abstract String answer3();

    //模板方法,考试的过程,定义基本的考试过程,子类回调
    public void exam(){
        testQuestion1();
        testQuestion2();
        testQuestion3();
    }
}

首先来看第一个学生的考试情况

public class TestPaperA extends TestPaper{

    @Override
    public String answer1() {
        return "A";
    }

    @Override
    public String answer2() {
        return "B";
    }

    @Override
    public String answer3() {
        return "D";
    }

}

其他学生的试卷可能答案不是一样的,但是基本的答题过程就是一样的,所以就不重复写了,下面看下客户端代码。

public class ShowAnswer {

    public static void main(String[] args) {
        TestPaper testPaper = new TestPaperA();
        testPaper.exam();
    }

}

可以看待客户端代码也减轻了很多,这样逻辑清晰,利于维护,优势很明显,下面看下具体答题情况。

小龙女是杨过的什么亲戚?() A.小姨妈  B.大姨妈  C.姑妈  D.舅妈
答案:A
全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛
答案:B
《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴
答案:D

3、模板方法模式的基本结构

AbstractClass是一个抽象类,其实就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体的实现,他给出了一些逻辑的骨架,而逻辑的组成在相应的抽象类中,推迟到了子类实现。代码如下

public abstract class AbstractClass {

    //一些抽象行为,可以理解为重复不变的方法,提取到抽象类
    public abstract void primitiveOperation1();
    public abstract void primitiveOperation2();

    //模板方法,给出了具体逻辑的骨架,而逻辑的组成是一些相应的抽象操作,他们都推迟到子类实现
    public void templateMothed(){
        primitiveOperation1();
        primitiveOperation2();
    }

}

ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有一个或者多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是骨架的组成步骤)的不同实现,从而得到的实现都不同。

public class ConcreteClassA extends AbstractClass{

    @Override
    public void primitiveOperation1() {
        System.out.println("子类A的操作1");
    }

    @Override
    public void primitiveOperation2() {
        System.out.println("子类A的操作2");
    }

}
public class ConcreteClassB extends AbstractClass{

    @Override
    public void primitiveOperation1() {
        System.out.println("子类B的操作1");
    }

    @Override
    public void primitiveOperation2() {
        System.out.println("子类B的操作2");
    }

}

上面定义了两个具体的实现,更多的实现其实都是一致的,这里就不多多说了。下面看下客户端代码

public class Show {

    public static void main(String[] args) {
        AbstractClass c;
        c = new ConcreteClassA();
        c.templateMothed();
        c = new ConcreteClassB();
        c.templateMothed();
    }

}

输入如下

子类A的操作1
子类A的操作2
子类B的操作1
子类B的操作2

4、UML图

三、总结

  模板方法模式就是为了将重复不变的代码提取到一个抽象类中。当我们要完成在某一细节层次一致的一个国政或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。

时间: 2024-10-10 17:50:40

设计之美——模板方法模式的相关文章

设计之美——代理模式

一.什么是代理模式(Porxy) 概念:代理模式就是为其他对象提供一种代理以控制对这个对象的访问. 现实生活中也有很多行为吻合代理模式.比如店外卖,客户在APP上下单后,店长会接单.这个时候店长可以选择自己去送这份外卖,也可以委托送餐员代理店长去送这份外卖.当然店长是可以自己送,但店长送了外卖店就没人看着了,而让送餐员代理送外卖就不会这样了.这里很显然店长是对象本尊(Subject),送餐员是代理对象(Proxy ),代理对象中有店长给的订单信息,比如送到哪里,几点之前要送到,这就说明代理对象中

面向对象编程思想-模板方法模式

一.引言 说到模板,顾名思义:就是样板,整体架构已经有了,你只需要填充自己的特定内容就可以了.如:简历模板,论文模板,PPT模板等 在软件设计中,模板方法模式与之很相似,下面请看我们今天要学习的模板方法模式 二.模板方法模式 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 下面结构图: 抽象模板角色(AbstractClass):在抽象类中定义一个或多个基本操作,每一个操作对应算法中一个步骤:同时提供一个模板方法

深入浅出Java模式设计之模板方法模式

一.引子  这是一个很简单的模式,却被非常广泛的使用.之所以简单是因为在这个模式中仅仅使用到了继承关系. 继承关系由于自身的缺陷,被专家们扣上了“罪恶”的帽子.“使用委派关系代替继承关系”,“尽量使用接口实现而不是抽象类继承”等等专家警告,让我们这些菜鸟对继承“另眼相看”. 其实,继承还是有很多自身的优点所在.只是被大家滥用的似乎缺点更加明显了.合理的利用继承关系,还是能对你的系统设计起到很好的作用的.而模板方法模式就是其中的一个使用范例. 二.定义与结构 GOF给模板方法(Template M

深入浅出设计模式——模板方法模式(Template Method Pattern)

模式动机 模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一.在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中.在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意.模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式. 模式定义模

JAVA之旅(七)——final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展

JAVA之旅(七)--final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展 OK,我们继续学习JAVA,美滋滋的 一.final 我们来聊聊final这个关键字 final可以修饰类,方法和变量 final修饰的类不可以被继承 final修饰的方法不可以被覆盖 final修饰的变量是一个常量,只能被赋值一次 内部类只能访问被final修饰的局部变量 final,故名思意,就是最终的意思,由以上的五种特性,不过final的出现,也是有

java设计模式 模板方法模式Template Method

设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样.项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因.

04 - 模板方法模式

模版模式: 又叫模板方法模式,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情冴下,重新定义算法中的某些步骤. 模式中的角色: 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架. 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法. 模式优缺点:优点 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码. 子类实现算法的某些细节,有助于算法的扩展. 通过一个父类调用子类实现的操作,通过子

9 模板方法模式

模板方法模式(Template Mothod):在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. UML类图如下: 要点有两个:原语操作PrimitiveOperation以及钩子Hook()方法. 代码举例 1 public abstract class CaffeineBeverage 2 { 3 public void PrepareRecipe() 4 { 5 BoilWater(); 6 Brew();

学习日记之模板方法模式和 Effective C++

模板方法模式: 定义:定义一个操作中的算法的骨架.而将一些步骤延伸到子类中.模板方法使得子类能够不改变算法的结构就可以重定义该算法的某些特定步骤. (1),用了继承,而且肯定这个继承有意义的情况下.就应该要成为子类的模板,所以反复的代码都应该提升到父类中,而不是让每一个子类去反复. (2).当我们要完毕某一个细节层次一致的过程或者一系列步骤,但其个别步骤在更具体的层次上的实现可能不同一时候.我们通常考虑模板方法模式来处理. (3),模板方法模式通过把不变的行为搬移到超类.去除子类中的反复代码来体