设计模式之模板方法模式

在上一篇记录中,做了菜单树的实现,其中有一行代码 Collections.sort(children);它的功能是根据菜单的父节点编号PID进行排序,实现代码如下:

复制代码
/**
 * 系统菜单实体类
 */

public class SystemMenuInfo implements Serializable,Comparable<SystemMenuInfo>{

    private static final long serialVersionUID = -612577710282986839L;

    private Integer menuId;

    private String menuName;

    private String url;

    private Integer menuLevel;

    private String iconCls;

    private Integer sortId;

    private Integer pid;

    private String description;

    private String remark;

    private String creator;

    private Date createDate;

    private String modifier;

    private Date modifyDate;

    private String menuState;

    private List<SystemMenuInfo> children;
复制代码
    /**
     * 根据sortId升序排序
     * @param menu
     * @return
     */
    @Override
    public int compareTo(@NotNull SystemMenuInfo menu) {
        if(this.sortId>menu.sortId){
            return 1;
        }else if(this.sortId<menu.sortId){
            return -1;
        } else{
            return 0;
        }
    }
}

在这里菜单类实现了Comparable接口,只需要实现compareTo中的比较逻辑,在Collections调用sort方法时就可以实现排序的功能,如果要改变比较的方式,只需要修改比较方法中的代码,从而达到排序方式改变的目的,而sort()方法中的代码基本固定,不需要做修改,这就是一处典型模板方法模式的应用。

模板模式简介:

模板方法模式主要用于对算法或行为逻辑进行封装,即如果多个类中存在某些相似的算法逻辑或者行为逻辑,可以将这些相似的逻辑提取到模板方法类中实现,然后让相应的子类根据需要实现某些自定义的逻辑。

思想:

模板方法模式准备一个抽象类,将部分逻辑以具体方法的形式实现,然后声明一些抽象方法来迫使子类实现 剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一 个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

实现:

//准备⼀个抽象类,将部分逻辑以具体⽅法的形式实现

public abstract class SortUtil {

//声明⼀些抽象方法来迫使子类实现剩余的逻辑

public abstract int compareTo(T o1, T o2);

public void sort(T arr) {

//.先制定⼀个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现

for (int i = 0; i < arr.length; i++) {

for (int j = 0; j < arr.length - 1 - i; j++) {

int m = compareTo(arrj, arrj + 1);

if (m > 0) {

T temp = arrj;

arrj = arrj + 1;

arrj + 1 = temp;

}

}

}

}

}

class StringSortUtil extends SortUtil {

@Override

public int compareTo(String o1, String o2) {

return - o1.length() + o2.length();

}

}

public class Test {

public static void main(String\[\] args) {

String\[\] arr = {"aa","bbbbb","ccc"};

StringSortUtil util = new StringSortUtil();

util.sort(arr);

}

}

也可以定义一个接口,然后在模板方法sort的参数中传入这个接口,接口定义如下:

public interface SomeComparator {

public int compareTo(T o1, T o2) ;

}

public class SortUtil {

public static void sort(Object\[\] arr,SomeComparator sc) {

for (int i = 0; i < arr.length; i++) {

for (int j = 0; j < arr.length - 1 - i; j++) {

int m = sc.compareTo(arrj, arrj + 1);

if (m > 0) {

Object temp = arrj;

arrj = arrj + 1;

arrj + 1 = temp;

}

}

}

}

}

public class Test {

public static void main(String\[\] args) {

String\[\] arr = {"aa","bbbbb","ccc"};

// 迫使调用者 实现 剩余逻辑

SortUtil.sort(arr, new SomeComparator() {

@Override

public int compareTo(String o1, String o2) {

return o1.length() - o2.length();

}

});

相比于继承抽象类的方式,传入接口的方法更方便,它不需要每次使用的时候都给一个相应的子类实现,传入的这个接口也叫回调接口。

总结:

当一个方法中 有多行代码不确定时,(可能只有当使用到该方法时才能确定),一定需要使用模板模式。

模板模式的使用方式:

实现顶层业务逻辑

创建接口及抽象方法

将接口类型的对象作为参数,传入到第一步的方法中

在不确定应该写什么代码的位置 调用接口中的抽象方法

相关推荐
sarasuki7 小时前
为什么 Agent 工具需要一个「协议」而不是「框架」:MCP 成为标准的底层逻辑
设计模式·agent·mcp
vivo互联网技术7 小时前
知识不是文件,也不是向量 | KDC 系列 02
人工智能·设计模式·架构
Zane19946 天前
一个 new 就能创建对象,为什么还要拆出单例、工厂、建造者、原型四种模式?
设计模式
怕浪猫7 天前
一行命令复刻爆款视频,我把 Hypit 从安装跑到了出片
人工智能·设计模式·程序员
Zane19947 天前
函数式编程里的函数,其实不是你天天写的那个函数——三大编程范式的边界在哪
设计模式
Zane19948 天前
策略模式现在该不该上?一次讲清楚过度设计和设计不足怎么找平衡
设计模式
她说..8 天前
常见设计模式-模板方法模式
java·spring·设计模式·springboot
xiaofeiyang1508 天前
第六章 · 桥接 — 三支毛笔,画出九种颜色
设计模式
Shadow(⊙o⊙)9 天前
OTOL设计模式 One Thread One Loop
服务器·网络·设计模式
sarasuki10 天前
如何让LLM 能在半夜偷偷打开网易云呢?
人工智能·设计模式·agent