实例讲解JAVA 模板方法模式

 更新时间:2020年06月23日 10:12:08   作者:认真对待世界的小白  
这篇文章主要介绍了JAVA 模板方法模式的的相关资料,文中示例代码非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下

在讲述这个模式之前,我们先看一个案例:抄题目:两个学生将老师出的题目抄写在纸上,并且写出答案

先看一个比较笨的写法

public class TestPaperA {
 public void testQuestion1(){
  System.out.println("1+1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:b");
 }
 
 public void testQuestion2(){
  System.out.println("1*1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:a");
 }
 
 public void testQuestion3(){
  System.out.println("1/1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:a");
 }
}

public class TestPaperB {
 public void testQuestion1(){
  System.out.println("1+1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:c");
 }
 
 public void testQuestion2(){
  System.out.println("1*1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:a");
 }
 
 public void testQuestion3(){
  System.out.println("1/1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:d");
 }
}

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();
 }
}

输出结果:

学生甲抄的试卷:
1+1等于几? a.1 b.2 c.3 d.4
答案:b
1*1等于几? a.1 b.2 c.3 d.4
答案:a
1/1等于几? a.1 b.2 c.3 d.4
答案:a
学生乙抄的试卷:
1+1等于几? a.1 b.2 c.3 d.4
答案:c
1*1等于几? a.1 b.2 c.3 d.4
答案:a
1/1等于几? a.1 b.2 c.3 d.4
答案:d

可以看出,学生甲和学生乙除了答案不一样,抄的题目都一样,抄题目的过程容易出错,而且如果老师改了题目,那么两个学生都需要把题目改掉

怎么优化?我们先来一个初步优化:学过继承的都会想到,把公共部分放到父类中,子类继承父类后,自然就拥有了公共部分

public class TestPaper {
 public void testQuestion1(){
  System.out.println("1+1等于几? a.1 b.2  c.3 d.4");
 }
 
 public void testQuestion2(){
  System.out.println("1*1等于几? a.1 b.2  c.3 d.4");
 }
 
 public void testQuestion3(){
  System.out.println("1/1等于几? a.1 b.2  c.3 d.4");
 }
}


public class TestPaperA extends TestPaper{
 @Override
 public void testQuestion1(){
  super.testQuestion1();
  System.out.println("答案:b");
 }
 @Override
 public void testQuestion2(){
  super.testQuestion2();
  System.out.println("答案:a");
 }
 @Override
 public void testQuestion3(){
  super.testQuestion3();
  System.out.println("答案:a");
 }
}

public class TestPaperB extends TestPaper{
 @Override
 public void testQuestion1(){
  super.testQuestion1();
  System.out.println("答案:c");
 }
 @Override
 public void testQuestion2(){
  super.testQuestion2();
  System.out.println("答案:a");
 }
 @Override
 public void testQuestion3(){
  super.testQuestion3();
  System.out.println("答案:d");
 }
}

测试类同上

我们看这个初步优化,发现还是有重复的部分,比如super.testQuestion1()和System.out.println("答案”)

我们既然用了继承,并且肯定这个继承有意义,就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。

对于“抄题目”这个例子来说,除了学生的答案会有不同的结果,其他全部都是一样的。继续优化:

public abstract class TestPaper {
 public void testQuestion1(){
  System.out.println("1+1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:"+answer1());
 }
 
 public void testQuestion2(){
  System.out.println("1*1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:"+answer2());
 }
 
 public void testQuestion3(){
  System.out.println("1/1等于几? a.1 b.2  c.3 d.4");
  System.out.println("答案:"+answer3());
 }
 
 public abstract String answer1();
 
 public abstract String answer2();
 
 public abstract String answer3();
}


public class TestPaperA extends TestPaper{
 @Override
 public String answer1() {
  return "b";
 }
 @Override
 public String answer2() {
  return "a";
 }
 @Override
 public String answer3() {
  return "a";
 }
}

public class TestPaperB extends TestPaper{
 @Override
 public String answer1() {
  return "c";
 }
 @Override
 public String answer2() {
  return "a";
 }
 @Override
 public String answer3() {
  return "d";
 }
}

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();
 }
}

输出结果:

学生甲抄的试卷:
1+1等于几? a.1 b.2 c.3 d.4
答案:b
1*1等于几? a.1 b.2 c.3 d.4
答案:a
1/1等于几? a.1 b.2 c.3 d.4
答案:a
学生乙抄的试卷:
1+1等于几? a.1 b.2 c.3 d.4
答案:c
1*1等于几? a.1 b.2 c.3 d.4
答案:a
1/1等于几? a.1 b.2 c.3 d.4
答案:d

结果和之前一模一样,但简洁了很多。此时要有更多的学生来答卷,只不过是在试卷的木板上填写选择题的选项答案,这是每个人的试卷唯一不同(谁说的,名字也不同,但这样的做法的确是对试卷的最大复用)

下面介绍模板方法模式:https://www.jb51.net/article/189195.htm

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

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

public abstract class AbstractClass {
 //一些抽象行为,放到子类去实现
 public abstract void primitiveOperation1();
 public abstract void primitiveOperation2();
 
 //模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作,它们都推迟到子类去实现
 public void templateMethod(){
  primitiveOperation1();
  primitiveOperation2();
 }
}

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

public class ConcreteClassA extends AbstractClass{
 @Override
 public void primitiveOperation1() {
  //具体类A方法1实现,与ConcreteClassB不同的方法实现
 }

 @Override
 public void primitiveOperation2() {
  //具体类A方法2实现,与ConcreteClassB不同的方法实现
 }
}

public class ConcreteClassB extends AbstractClass{
 @Override
 public void primitiveOperation1() {
  //具体类B方法1实现,与ConcreteClassA不同的方法实现
 }

 @Override
 public void primitiveOperation2() {
  //具体类B方法2实现,与ConcreteClassA不同的方法实现
 }
}

测试代码

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

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

模板方法模式就是提供了一个很好的代码复用平台。因为有时候,我们会遇到由一系列步骤构成的过程需要执行。这个过程从高层次上看是相同的,但有些步骤的实现可能不同。这时候,我们通常就应该要考虑用模板方法模式了。

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

以上就是实例讲解JAVA 模板方法模式的详细内容,更多关于JAVA 模板方法模式的资料请关注脚本之家其它相关文章!

相关文章

  • 一步步教会你使用Java原生指令编译并运行一个程序

    一步步教会你使用Java原生指令编译并运行一个程序

    Java是一种广泛使用的编程语言,具有跨平台性和面向对象的特性,下面这篇文章主要给大家介绍了关于使用Java原生指令编译并运行一个程序的相关资料,需要的朋友可以参考下
    2024-07-07
  • java程序中foreach用法示例

    java程序中foreach用法示例

    这篇文章主要介绍了java程序中foreach用法示例,需要的朋友可以参考下
    2014-04-04
  • Java唯一订单编号生成代码例子

    Java唯一订单编号生成代码例子

    在项目中,我们经常遇到需要生成订单编号、字典编号等唯一值场景,下面这篇文章主要给大家介绍了关于Java唯一订单编号生成的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07
  • SpringBoot Aop 详解和多种使用场景解析

    SpringBoot Aop 详解和多种使用场景解析

    aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例,对SpringBoot Aop相关知识感兴趣的朋友跟随小编一起看看吧
    2021-08-08
  • Spring如何替换掉默认common-logging.jar

    Spring如何替换掉默认common-logging.jar

    这篇文章主要介绍了Spring如何替换掉默认common-logging.jar,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Spring WebFlux的使用指南

    Spring WebFlux的使用指南

    这篇文章主要介绍了Spring WebFlux的使用指南,帮助大家更好的理解和学习使用Spring框架,感兴趣的朋友可以了解下
    2021-05-05
  • Java中数组在内存中存放原理的讲解

    Java中数组在内存中存放原理的讲解

    今天小编就为大家分享一篇关于Java中数组在内存中存放原理的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • SpringCloud之分布式配置中心Spring Cloud Config高可用配置实例代码

    SpringCloud之分布式配置中心Spring Cloud Config高可用配置实例代码

    这篇文章主要介绍了SpringCloud之分布式配置中心Spring Cloud Config高可用配置实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • Java实现的日期处理类完整实例

    Java实现的日期处理类完整实例

    这篇文章主要介绍了Java实现的日期处理类,结合完整实例形式分析了Java针对日期的获取、运算、转换等相关操作技巧,需要的朋友可以参考下
    2017-09-09
  • Java数据结构--时间和空间复杂度

    Java数据结构--时间和空间复杂度

    这篇文章主要介绍了java数据结构的时间和空间复杂度,小编觉得这篇文写的不错,感兴趣的朋友可以了解下,希望能够给你带来帮助
    2021-08-08

最新评论