【设计模式系列】行为型之模板模式

理论

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

2.角色
抽象模板(Abstract Template)角色

  • 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。
  • 定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

具体模板(Concrete Template)角色

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

3.适合场景:

  • 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

实践

  • 抽象模板类
package com.qxy.design.template;

/**
 * @author qxy
 * @date 2020/10/16 2:30 下午
 */
public abstract class FileAnalysisTemplate {
    
    

//定义模版方法,对外部访问
    public final void analysisFile() {
    
    
        //1.验证文件后缀
        validateFileSuffix();
        //2.解析文件内容
        analysisFileLine();
        //3.验证文件标题列
        validateFileTitle();
        //处理钩子方法
        if (specialFileColumn()) {
    
    
            handlerSpecialColumn();
        }
        //4.封装pojo
        createPojo();
        //5.交互数据库
        operateDataSource();
    }


    protected void validateFileSuffix() {
    
    
        System.out.println("验证文件后缀成功:文件后缀为.xls或者.xlsx");
    }

    protected void analysisFileLine() {
    
    
        System.out.println("文件解析成功:共用一套解析文件方法或者工具类");
    }

    protected abstract void validateFileTitle();

    protected abstract void createPojo();

    protected void operateDataSource() {
    
    
        System.out.println("数据入库成功");
    }

    /**
     * 是否特殊处理列数据
     * @return false
     */
    protected boolean specialFileColumn() {
    
    
        return false;
    }

    /**
     * 钩子方法:交给子类具体实现处理
     */
    protected void handlerSpecialColumn() {
    
    

    }

}
  • 具体模板角色:ItemAFileAnalysis
package com.qxy.design.template;

/**
 * @author qxy
 * @date 2020/10/16 3:08 下午
 */
public class ItemAFileAnalysis extends FileAnalysisTemplate{
    
    
    @Override
    protected void validateFileTitle() {
    
    
        System.out.println("验证项目A的标题列是否缺失");
    }

    @Override
    protected void createPojo() {
    
    
        System.out.println("创建项目A对象");
    }

    @Override
    protected boolean specialFileColumn() {
    
    
        return true;
    }

    @Override
    protected void handlerSpecialColumn() {
    
    
        System.out.println("特殊处理:处理项目名字");
    }
}
  • 具体模板角色:ItemBFileAnalysis
package com.qxy.design.template;

/**
 * @author qxy
 * @date 2020/10/16 3:10 下午
 */
public class ItemBFileAnalysis extends FileAnalysisTemplate{
    
    
    @Override
    protected void validateFileTitle() {
    
    
        System.out.println("验证项目B的标题列是否缺失");
    }

    @Override
    protected void createPojo() {
    
    
        System.out.println("创建项B对象");
    }
}
  • 客户端
package com.qxy.design.template;
/**
 * @author qxy
 * @date 2020/10/16 3:07 下午
 */
public class FileClient {
    
    
    public static void main(String[] args) {
    
    
        FileAnalysisTemplate aFileAnalysis = new ItemAFileAnalysis();
        aFileAnalysis.analysisFile();
        System.out.println("-----------");
        FileAnalysisTemplate bFileAnalysis = new ItemBFileAnalysis();
        bFileAnalysis.analysisFile();
    }
}

执行结果如下:

验证文件后缀成功:文件后缀为.xls或者.xlsx
文件解析成功:共用一套解析文件方法或者工具类
验证项目A的标题列是否缺失
特殊处理:处理项目名字
创建项目A对象
数据入库成功
-----------
验证文件后缀成功:文件后缀为.xls或者.xlsx
文件解析成功:共用一套解析文件方法或者工具类
验证项目B的标题列是否缺失
创建项B对象
数据入库成功

Process finished with exit code 0

总结

优点:

  1. 封装不变的部分,将不变的部分抽取出来;
  2. 扩展可变部分,将可变的设置抽象方法,让具体子类来实现。
  3. 抽取的公共代码,便于后期维护。
  4. 行为有基类来控制,具体操作有子类实现。

缺点:
每一个不同的实现都需要有一个子类来实现,这样就会导致类的数量大大的增加,使得系统更加庞大。

特别注意
为了防止算法骨架被恶意的破坏或者恶意的操作,一般在使用模板模式的时候,模板方法都会加上final这个关键字来限制。
模板模式的关键是:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑
每当定义一个新的子类时,不要按照控制流程的思路去想,而应当按照“责任”的思路去想。换言之,应当考虑哪些操作是必须置换掉的,哪些操作是可以置换掉的,以及哪些操作是不可以置换掉的。使用模板模式可以使这些责任变得清晰。

源代码传送门:https://github.com/stream-source/stream-source
参考资料:Java设计模式

猜你喜欢

转载自blog.csdn.net/xuan_lu/article/details/109367468