设计模式(8):模版方法模式

一、概念

1、定义:模版方法模式在一个方法中定义了算法流程中的每一个步骤(完成一件事的每一个步骤),把这些步骤的实现推迟到了子类。即模版是一套固定的算法,但是可以通过子类扩展固定算法的某些步骤。
2、类型:行为型
3、适用场景:

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。比如往冰箱里放东西这个操作,打开门和关上门的操作是不变的,具体放什么可以改变。
  • 各子类中公共的行为被提取出来,放到一个公共父类中,从而避免代码的重复。

4、优缺点

  • 优点
    • 提高复用性和扩展性(相同的代码放在抽象的父类中)
    • 提高扩展性(不同代码放入不同子类,来增加新的行为)
    • 符合OCP
  • 缺点
    • 类数目增加
    • 增加了系统实现的复杂度
    • 模版方法通过继承实现,而继承自身的缺点是,如果父类添加新的抽象方法,子类都要改一遍

5、扩展 hook方法,模版对子类更进一层的开放和扩展
6、相关设计模式

  • 工厂方法是模版方法的特殊实现
  • 和策略模式的区别
    • 策略模式是使得算法间可以相互替换且不影响应用层的使用,模版是针对一个算法流程,将具体实现不一样的具体实现步骤交给子类去实现。模版不改变算法流程,而策略模式可以改变算法流程。

7、UML
在这里插入图片描述

二、Coding

以制作课程为例
模版类

//模版类,制作课程的步骤
public abstract class ACourse {
    //ACourse中定义的模版是不想被修改的,所以方法被声明为final
    protected final void makeCourse() {
        this.makePPT();     //必须制作ppt
        this.makeVideo();   //必须制作视频
        if (needWriteArticle()) {       //制作手记是可选的,这边需要使用hook,子类可以重写hook
            this.writeArticle();
        }
        this.packageCourse();
    }
    //拆解小步骤
    //所有的课程都要制作ppt(如果这个方法所有的子类都不需要重写,就声明为final)
    final void makePPT() {
        System.out.println("制作PPT");
    }
    final void makeVideo() {
        System.out.println("制作视频");
    }
    //对于课程来说,编写手记是一个可选项,可写可不写
    final void writeArticle() {
        System.out.println("编写手记");
    }
    //hook方法,它不是final的,子类可以覆盖它
    protected boolean needWriteArticle() {
        return false;
    }
    //包装课程,对于不同的课程,包装的素材都是不一样的,交给子类来实现
    abstract void packageCourse();
}

具体子类

//两个课程类
//设计模式课程类
public class DesignPannternCourse extends ACourse {
    @Override
    void packageCourse() {
        System.out.println("提供课程的源代码");
    }
}

//FE前端课程类
public class FECourse extends ACourse {
    @Override
    void packageCourse() {
        System.out.println("提供前端代码");
        System.out.println("提供图片素材");
    }
    //前端课程要编写手记,那就重写hook
    @Override
    protected boolean needWriteArticle() {
        return true;
    }
}

测试类

//Test
public class Test {
    public static void main(String[] args) {
        ACourse designPannternCourse = new DesignPannternCourse();
        designPannternCourse.makeCourse();
        System.out.println("-----------------------");
        ACourse feCourse = new FECourse();
        feCourse.makeCourse();
    }
}
制作PPT
制作视频
提供课程的源代码
-----------------------
制作PPT
制作视频
编写手记
提供前端代码
提供图片素材

在这里插入图片描述
现在问题来了,前端课程中vue要写手记,而react不需要写手记,那怎么解决?

public class FECourse extends ACourse{
    private boolean needWriteArticleFlag = false;
    @Override
    void packageCourse() {
        System.out.println("提供前端课程的源代码");
        System.out.println("提供图片素材");
    }

    //通过构造器和setter把它开放给应用层
    public FECourse(boolean needWriteArticleFlag) {
        this.needWriteArticleFlag = needWriteArticleFlag;
    }

    //这样是否需要写手记由应用层去决定
    @Override
    protected boolean needWriteArticle() {
        return this.needWriteArticleFlag;
    }
}

//Test
public class Test {
    public static void main(String[] args) {
        ACourse feCourse = new FECourse(true);
        feCourse.makeCourse();
    }
}
制作PPT
制作视频
编写手记
提供前端课程的源代码
提供图片素材

tip:模版中不可修改的方法用final修饰,对于子类必须提供算法中的某个步骤的实现时,就使用抽象的方法,如果算法的这个部分是可选的,就可以用hook,子类可以自己选择要不要覆盖hook,一般可以利用hook做一些决定。

三 、模版方法模式在JDK中的体现

ArrayListget方法就是实现了父类AbstractList的抽象get方法,同样AbstractSetAbstractMap也是同理,该开放的开放,该自己实现的自己实现。以及Comparable接口的ComparTo方法就是使用了模版方法模式,让我们可以自定义排序的规则等等。还有Servlet中的doGetdoPost方法。

发布了43 篇原创文章 · 获赞 6 · 访问量 3907

猜你喜欢

转载自blog.csdn.net/weixin_44424668/article/details/103259868