java设计模式之模板

背景

按理说如果被人写的好,那我还写个啥子?没啥,就是感觉自己写一遍能记得更清楚。
模板的定义,大概就是某件事情,大家大部分步骤是一样的,甚至某些步骤的做法是一模一样的。这时候就有人把这个事情抽象出一个模板来了,方便后面的人按照模板去完成。

定义一个操作中的算法骨架,而将一些实现步骤延迟到子类中。它使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。它的要义就是定义算法骨架,让子类自己实现。

情景

比方新人入职步骤:交必要的入职材料给hr(入职流程审核需要),入职体检,去公司办理入职。

package com.aliyu.learn.pattern.template;

/**
 * 描述:入职步骤模板
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-20 4:26 下午
 */
public abstract class EntryTemplate {
    
    

    /**
     * 入职人的姓名(模板共有属性,在模板初始化时传入)
     */
    protected String personName;

    public EntryTemplate(String personName) {
    
    
        this.personName = personName;
    }

    /**
     * 提交材料,具体材料肯定是每个人都不一样
     * 交由新人自己实现
     * protected保证只能被子类访问
     * 非公共的抽成抽象方法,由子类自己实现
     */
    protected abstract void uploadData();

    /**
     * 入职体检,啥时候体检,去哪里体检都不一定一样
     * 交由新人自己实现
     */
    protected abstract void checkBody();

    /**
     * 公司报道,具体报道时间不一样
     * 交由新人自己实现
     */
    protected abstract void checkIn();

    /**
     * 但是大家都会经历这3个步骤
     * 公共的结构化的逻辑在抽象类中实现
     * 用final修饰,保证子类不会修改
     */
    public final void CheckInStep(){
    
    
        uploadData();
        checkBody();
        checkIn();
    }



}

ps:公共的步骤逻辑在抽象类中实现(CheckInStep),并用final修饰,不让子类修改。非公共的逻辑抽象为抽象方法,用protected修饰,保证只能由子类自己去实现。

模拟一个张三的模板:

package com.aliyu.learn.pattern.template;

/**
 * 描述:张三入职
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-20 4:49 下午
 */
public class EntryOne extends EntryTemplate{
    
    
    
    public EntryOne(String personName) {
    
    
        super(personName);
    }

    @Override
    protected void uploadData() {
    
    
        System.out.println("新人张三上传文档");
    }

    @Override
    protected void checkBody() {
    
    
        System.out.println("张三入职体检");
    }

    @Override
    protected void checkIn() {
    
    
        System.out.println("张三公司报道");
    }
}

李四的模板:

package com.aliyu.learn.pattern.template;

/**
 * 描述:李四入职
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-20 4:49 下午
 */
public class EntryLi extends EntryTemplate{
    
    

    public EntryLi(String personName) {
    
    
        super(personName);
    }

    @Override
    protected void uploadData() {
    
    
        System.out.println("李四上传文档");
    }

    @Override
    protected void checkBody() {
    
    
        System.out.println("李四入职体检");
    }

    @Override
    protected void checkIn() {
    
    
        System.out.println("李四公司报道");
    }
}

测试张三、李四按照模板进行“入职”:

package com.aliyu.learn.pattern.template;

/**
 * 描述:
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-20 5:00 下午
 */
public class TestTemplate {
    
    

    public static void main(String[] args) {
    
    

        EntryLi entryLi = new EntryLi("李四");
        entryLi.checkInStep();

        EntryZhang entryZhang = new EntryZhang("张三");
        entryZhang.checkInStep();

    }
}

在这里插入图片描述

钩子方法

为啥叫钩子方法?不晓得。它的由来是,比方上面的三个步骤中,如果你有一年内体检报告,那么就没必要体检了。但是这个步骤可能是少数情况,你又不想为了这个重新写一个模板。当然你可以说不体检的人,实现体检方法时,啥也不做就好。这种写法是不优雅的,也容易造成误解。有就是有,没有就是没有。你实现了“体检”方法,却啥也不做?
实现代码:

package com.aliyu.learn.pattern.template;

/**
 * 描述:入职步骤模板
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-20 4:26 下午
 */
public abstract class EntryTemplate {
    
    

    /**
     * 入职人的姓名(模板共有属性,在模板初始化时传入)
     */
    protected String personName;

    public EntryTemplate(String personName) {
    
    
        this.personName = personName;
    }

    /**
     * 提交材料,具体材料肯定是每个人都不一样
     * 交由新人自己实现
     * protected保证只能被子类访问
     * 非公共的抽成抽象方法,由子类自己实现
     */
    protected abstract void uploadData();

    /**
     * 入职体检,啥时候体检,去哪里体检都不一定一样
     * 交由新人自己实现
     */
    protected abstract void checkBody();

    /**
     * 公司报道,具体报道时间不一样
     * 交由新人自己实现
     */
    protected abstract void checkIn();

    /**
     * 钩子方法,默认返回true
     * 默认"体检"
     * @return
     */
    protected boolean isCheckBody(){
    
    
        return true;
    }

    /**
     * 但是大家都会经历这3个步骤
     * 公共的结构化的逻辑在抽象类中实现
     */
    public final void checkInStep(){
    
    
        System.out.println("入职人:" + personName);
        uploadData();
        //是否执行体检交由"钩子方法"判断,而钩子方法可以被子类重写
        if(this.isCheckBody()){
    
    
            checkBody();
        }
        checkIn();
    }



}

ps:注意到,它加了一个钩子方法“isCheckBody”,默认返回true。
同时骨架方法“checkInStep”中的加了一个判断,将是否体检交由钩子方法判断。而钩子方法可以被子类重写,也就是子类可以自行决定是否参加体检。

不参加体检的王五:

package com.aliyu.learn.pattern.template;

/**
 * 描述:王五的体检
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-21 9:41 上午
 */
public class EntryWang extends EntryTemplate{
    
    

    private boolean checkBodyFlag = true;

    public EntryWang(String personName) {
    
    
        super(personName);
    }

    public EntryWang(String personName, boolean checkBodyFlag) {
    
    
        super(personName);
        this.checkBodyFlag = checkBodyFlag;
    }

    @Override
    protected void uploadData() {
    
    
        System.out.println("王五上传文档");
    }

    @Override
    protected void checkBody() {
    
    
        System.out.println("王五入职体检");
    }

    @Override
    protected void checkIn() {
    
    
        System.out.println("王五公司报道");
    }

    @Override
    protected boolean isCheckBody(){
    
    
        return this.checkBodyFlag;
    }
}

ps:加了一个属性“是否体检”和对应的构造方法,使得王五初始化的时候就可以指定自己是否参加体检。

测试代码:

package com.aliyu.learn.pattern.template;

/**
 * 描述:
 * <p>作者: aliyu
 * <p>创建时间: 2021-10-20 5:00 下午
 */
public class TestHookTemplate {
    
    

    public static void main(String[] args) {
    
    

        EntryLi entryLi = new EntryLi("李四");
        entryLi.checkInStep();

        EntryWang entryWang = new EntryWang("王五", false);
        entryWang.checkInStep();

    }
}

在这里插入图片描述
可以看到,王五确实没有体检了。

其他

猜你喜欢

转载自blog.csdn.net/mofsfely2/article/details/120868318