行为型设计模式02-模板方法模式

简介: 行为型设计模式02-模板方法模式

模板方法模式

1、模板方法模式介绍


模板方法模式是一种行为型设计模式,定义了一个算法的框架,将其中一些步骤延迟到子类中实现。它使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤的具体实现方式。


模板方法模式通常由两部分组成:


抽象模板类(Abstract Template Class):定义了算法的框架和每个步骤应该如何执行,但并不实现全部方法,并且该类中的某些方法可以有默认实现。

具体实现类(Concrete Implementation Class):实现抽象模板类中的未实现方法,以及定义算法中的一些细节。

2、具体例子

考试的试卷,每个人都是考同一个试卷,但是老师将题目写在黑板上,同学们自己抄试卷。

2.1 不使用模板方法

学生甲抄写的试卷:

package com.shier.template;
/**
 * 学生甲抄的试卷
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperA {
    //试题1
    public void testQuestion1() {
        System.out.println(" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] "+
            " a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 ");
        System.out.println("答案:b");
    }
    //试题2
    public void testQuestion2() {
        System.out.println(" 杨过、程英、陆无双铲除了情花,造成[ ] "+
            "a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化  ");
        System.out.println("答案:a");
    }
    //试题3
    public void testQuestion3() {
        System.out.println(" 蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] "+
            "a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对   ");
        System.out.println("答案:c");
    }
}


学生乙的抄写的试卷:

/**
 * 学生乙抄的试卷
 *
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperB {
    //试题1
    public void testQuestion1() {
        System.out.println(" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] " +
                " a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 ");
        System.out.println("答案:d");
    }
    //试题2
    public void testQuestion2() {
        System.out.println(" 杨过、程英、陆无双铲除了情花,造成[ ] " +
                "a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化  ");
        System.out.println("答案:b");
    }
    //试题3
    public void testQuestion3() {
        System.out.println(" 蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] " +
                "a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对   ");
        System.out.println("答案:a");
    }
}


测试类:

/**
 *
 * @author Shier
 * CreateTime 2023/4/22 22:05
 */
public class Test {
   public static void main(String[] args){
      System.out.println("学生甲抄的试卷:");
        TestPaperA studentA = new TestPaperA();
        studentA.testQuestion1();
        studentA.testQuestion2();
        studentA.testQuestion3();
        System.out.println("学生乙抄的试卷:");
        TestPaperB studentB = new TestPaperB();
        studentB.testQuestion1();
        studentB.testQuestion2();
        studentB.testQuestion3();
   }
}


结果如下:

观察发现:学生甲和学生乙两个抄试卷类非常类似,除了答案不同,没什么不一样,这样写又容易错,又难以维护。


2.2 使用模板方法模式

最终使用模板方法的得出的UML类图如下:

使用继承,父类(抽象类)就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。

当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。

抽象类TestPaper:

/**
 * @author Shier
 * CreateTime 2023/4/22 22:11
 */
public abstract class TestPaper {
    // 给继承TestPaper的子类来重写,返回不同的答案
    protected abstract String answer1();
    protected abstract String answer2();
    protected abstract String answer3();
    public void testQuestion1() {
        System.out.println(" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] " +
                " a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 ");
        System.out.println("答案:" + this.answer1());
    }
    //试题2
    public void testQuestion2() {
        System.out.println(" 杨过、程英、陆无双铲除了情花,造成[ ] " +
                "a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化  ");
        System.out.println("答案:" + this.answer2());
    }
    //试题3
    public void testQuestion3() {
        System.out.println(" 蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] " +
                "a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对   ");
        System.out.println("答案:" + this.answer3());
    }
}


此时的甲乙同学的类,就相当于一个答题卡一样,只要把答案写上去,就可以,就不要再去抄题目。

/**
 * 学生甲抄的试卷
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperA extends TestPaper{
    /**
     * 第一题答案
     * @return
     */
    @Override
    protected String answer1() {
        return "b";
    }
    /**
     * 第二题
     * @return
     */
    @Override
    protected String answer2() {
        return "a";
    }
    /**
     * 第三题
     * @return
     */
    @Override
    protected String answer3() {
        return "c";
    }
}


/**
 * 学生乙抄的试卷
 *
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperB extends TestPaper{
    /**
     * 第一题答案
     * @return
     */
    @Override
    protected String answer1() {
        return "b";
    }
    /**
     * 第二题
     * @return
     */
    @Override
    protected String answer2() {
        return "a";
    }
    /**
     * 第三题
     * @return
     */
    @Override
    protected String answer3() {
        return "c";
    }
}

测试类:

/**
 *
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class Test {
   public static void main(String[] args){
      System.out.println("学生甲抄的试卷:");
        TestPaper studentA = new TestPaperA();
        studentA.testQuestion1();
        studentA.testQuestion2();
        studentA.testQuestion3();
        System.out.println("学生乙抄的试卷:");
        TestPaper studentB = new TestPaperB();
        studentB.testQuestion1();
        studentB.testQuestion2();
        studentB.testQuestion3();
   }
}


3、模板方法

模板方法的结构图:

AbstractClass是抽象类,其实也就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。


ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

4、总结


模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。


模板方法模式优点:


避免重复代码:将公共的方法提取到抽象模板类中,子类不再需要编写相同的代码段。

提高代码可扩展性:子类可以通过实现抽象模板类中的具体方法来改变算法的实现方式,从而达到扩展算法的目的,而不会影响到算法的整体结构。

降低代码耦合度:算法的框架和具体实现分别由抽象模板类和其子类实现,它们之间通过接口或者抽象父类进行交互,不直接依赖于具体的实现类。

缺点:


违反了单一职责原则:抽象模板类将算法的各个步骤定义在一个类中,其中包含了不同的逻辑分支,在一些情况下可能会使得该类变得比较庞大,难以维护和拓展。

可能导致代码复杂性增加:模板方法模式要求实现类必须提供某些具体的实现方法,这可能会导致实现类在实现这些方法时需要考虑更多的细节问题,从而增加了代码的复杂度。

破坏了封装性:实现类需要实现抽象模板类中定义的某些方法,这意味着实现类需要访问抽象模板类中的一些属性和方法,从而破坏了抽象模板类的封装性。

当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。

5、模板方法模式和原型模式的区别

我认为都是不断的 new 同一个对象,来初始化不同的数据来得到不同的内容,但是具体的区别如下所述


模板方法模式和原型模式是两种不同的设计模式,它们的作用和应用场景不同。


模板方法模式是一种行为型设计模式,它定义一个操作中的算法骨架,并允许子类为一个或多个步骤提供实现,而不需要改变算法的结构。模板方法模式的主要目的是在保持算法结构不变的同时,允许子类为某些步骤提供具体实现,从而实现代码复用和扩展。


原型模式是一种创建型设计模式,它通过复制现有对象来创建新对象,从而避免了从头开始创建新对象的代码。原型模式通过使用原型管理器来存储原型对象,并在需要时获取原型对象的副本,以避免多次创建相同的对象。


模板方法模式和原型模式的区别:


区别 模板方法模式 原型模式
目的不同 保持算法结构不变的同时,允许子类为某些步骤提供具体实现 通过复制现有对象来创建新对象,避免了从头开始创建新对象的代码
适用场景不同 具有相同算法结构但某些步骤具体实现可能不同的场景,例如算法、流程和框架的设计中 创建大量相似对象的场景,例如在图形界面中创建图形对象
实现方式不同 通过定义抽象类和具体子类实现 通过复制现有对象来创建新对象


目录
相关文章
|
3月前
|
设计模式 算法 Java
Java设计模式-模板方法模式(14)
Java设计模式-模板方法模式(14)
|
5月前
|
设计模式 JavaScript 算法
js设计模式【详解】—— 模板方法模式
js设计模式【详解】—— 模板方法模式
50 6
|
6月前
|
设计模式 算法
行为型设计模式之模板模式
行为型设计模式之模板模式
|
6月前
|
设计模式 存储
行为型设计模式之观察者模式
行为型设计模式之观察者模式
|
6月前
|
设计模式 算法
行为型设计模式
行为型设计模式
|
6月前
|
设计模式 算法 关系型数据库
设计模式第七讲-外观模式、适配器模式、模板方法模式详解
系统要求所有的数据库帮助类必须实现ISqlHelp接口,面向该接口编程,如SQLServerHelp类。 此时第三方提供了一个新的MySql的帮助类(假设是dll,不能修改),它的编程规范和ISqlHelp不兼容,这个时候就需要引入适配器类,使二者能相互兼容。
178 0
|
7月前
|
设计模式 算法 Java
Java 设计模式:深入模板方法模式的原理与应用
【4月更文挑战第27天】模板方法模式是一种行为设计模式,主要用于定义一个操作中的算法的框架,允许子类在不改变算法结构的情况下重定义算法的某些特定步骤。
71 1
|
7月前
|
设计模式 Go
[设计模式 Go实现] 行为型~迭代器模式
[设计模式 Go实现] 行为型~迭代器模式
|
7月前
|
设计模式 Go
[设计模式 Go实现] 行为型~解释器模式
[设计模式 Go实现] 行为型~解释器模式
|
7月前
|
设计模式 存储 SQL
第四篇 行为型设计模式 - 灵活定义对象间交互
第四篇 行为型设计模式 - 灵活定义对象间交互
141 0