在上一篇记录中,做了菜单树的实现,其中有一行代码 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(arr[j], arr[j + 1]);
if (m > 0) {
T temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 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(arr[j], arr[j + 1]);
if (m > 0) {
Object temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 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();
}
});
相比于继承抽象类的方式,传入接口的方法更方便,它不需要每次使用的时候都给一个相应的子类实现,传入的这个接口也叫回调接口。
总结:
当一个方法中 有多行代码不确定时,(可能只有当使用到该方法时才能确定),一定需要使用模板模式。
模板模式的使用方式:
实现顶层业务逻辑
创建接口及抽象方法
将接口类型的对象作为参数,传入到第一步的方法中
在不确定应该写什么代码的位置 调用接口中的抽象方法