设计模式之模版模式

模版模式是我最喜欢的一个设计模式,也是最早尝试使用过的一个设计模式。根据《大话设计模式》中的描述:

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

很关键的一点是算法,或者说函数的整体流程是不变的,但是部分流程是可变的、可扩展的,交由子类去实现。

举一个简单的例子,比如考试,在系统中的流程是:

系统创建考试 -> 上传试题(可选) -> 系统发布考试 -> 获取考生成绩 -> 生成考试报表(可选)

定义一个考试抽象类:

/**
 * @author Dongguabai
 * @Description
 * @Date 创建于 2020-05-04 09:31
 */
public abstract class AbstractExam {

    protected String examName;

    protected AbstractExam(String examName) {
        this.examName = examName;
    }

    /**
     * 考试流程
     */
    final void makeExam() {
        createExam(examName);
        if (needUploadQuestions()) {
            uploadQuestions();
        }
        publishExam();
        List<Object> examDatas = getExamData();
        if (needGenerateReport()){
            generateReport(examDatas);
        }
    }

    /**
     * 创建考试
     */
    final void createExam(String examName) {
        System.out.printf("系统创建考试:【%s】", examName);
        System.out.println();
    }

    void publishExam() {
        System.out.println("系统发布考试");
    }

    /**
     * 上传试题
     */
    final void uploadQuestions() {
        System.out.println("系统上传试题");
    }

    /**
     * 上传试题钩子
     *
     * @return
     */
    protected boolean needUploadQuestions() {
        return true;
    }

    /**
     * 获取考试数据
     */
    protected abstract List<Object> getExamData();

    /**
     * 生成数据报表
     */
    protected void generateReport(List<Object> examDatas) {
        System.out.println("默认数据报表:"+examDatas);
    }

    /**
     * 数据报表钩子
     *
     * @return
     */
    protected boolean needGenerateReport() {
        return false;
    }
}

考试又会分为线上考试和线下考试,这里设置了两个钩子,就是有的考试需要上传试题,比如线上考试,但是线下考试不需要上传试题;再比如都是线上考试,但是有的考试需要数据报表,有的考试不需要数据报表。

线上考试类:

package com.example.simplespringboot.dongguabai.template;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Dongguabai
 * @Description 线上考试
 * @Date 创建于 2020-05-04 09:48
 */
public class OnlineExam extends AbstractExam {

    private boolean needGenerateReport;

    protected OnlineExam(String examName) {
        super(examName);
    }

    public OnlineExam(String examName, boolean needGenerateReport) {
        super(examName);
        this.needGenerateReport = needGenerateReport;
    }

    @Override
    protected List<Object> getExamData() {
        List<Object> examDatas = new ArrayList<>();
        examDatas.add(this.examName + "-成绩1");
        examDatas.add(this.examName + "-成绩2");
        return examDatas;
    }

    @Override
    protected boolean needGenerateReport() {
        return needGenerateReport;
    }

    @Override
    protected void generateReport(List<Object> examDatas) {
        System.out.println("新的数据报表:" + examDatas);
    }
}

线下考试:

package com.example.simplespringboot.dongguabai.template;

import java.util.List;

/**
 * @author Dongguabai
 * @Description 线下考试
 * @Date 创建于 2020-05-04 09:56
 */
public class OfflineExam extends AbstractExam {
    public OfflineExam(String examName) {
        super(examName);
    }

    @Override
    protected List<Object> getExamData() {
        return null;
    }

    @Override
    protected boolean needUploadQuestions() {
        return false;
    }
}

测试一下:

public class Test {
    public static void main(String[] args) {
        AbstractExam onlineExam = new OnlineExam("线上考试1");
        AbstractExam onlineExam2 = new OnlineExam("线上考试2",true);
        onlineExam.makeExam();
        System.out.println("===========");
        onlineExam2.makeExam();
        System.out.println("===========");
        AbstractExam offlineExxam = new OfflineExam("线下考试");
        offlineExxam.makeExam();
    }
}

输出:

系统创建考试:【线上考试1】
系统上传试题
系统发布考试
===========
系统创建考试:【线上考试2】
系统上传试题
系统发布考试
新的数据报表:[线上考试2-成绩1, 线上考试2-成绩2]
===========
系统创建考试:【线下考试】
系统发布考试

模版模式无论是在 JDK 源码(如 ClassLoader)在很多开源框架中都有用到。比如 Dubbo 的负载均衡就用到了:

在这里插入图片描述

也可以参照 Dubbo,自己写一个,定义一个顶层接口,然后使用一个抽象类去继承,通过模版方法做一些前置操作:

package dgb.nospring.myrpc.registry.loadbalance;
 
import java.util.List;
 
/**
 * 负载顶层接口
 * @author Dongguabai
 * @date 2018/11/2 10:11
 */
public interface LoadBalance {
 
    String selectHost(List<String> repos);
}
package dgb.nospring.myrpc.registry.loadbalance;
 
import org.apache.commons.collections.CollectionUtils;
 
import java.util.List;
 
/**
 * @author Dongguabai
 * @date 2018/11/2 10:15
 */
public abstract class AbstractLoadBanance implements LoadBalance{
 
    /**
     * 通过模板方法,做一些前置操作
     * @param repos
     * @return
     */
    @Override
    public String selectHost(List<String> repos) {
        if(CollectionUtils.isEmpty(repos)){
            return null;
        }
        if(repos.size()==1){
            return repos.get(0);
        }
        return doSelect(repos);
    }
 
    /**
     * 实现具体的实现负载算法
     * @param repos
     * @return
     */
    protected  abstract String doSelect(List<String> repos);
 
}
package dgb.nospring.myrpc.registry.loadbalance;
 
import java.util.List;
import java.util.Random;
 
/**
 * 随机负载算法
 * @author Dongguabai
 * @date 2018/11/2 10:17
 */
public class RandomLoadBanalce extends AbstractLoadBanance{
 
    @Override
    protected String doSelect(List<String> repos) {
        return repos.get(new Random().nextInt(repos.size()));
    }
}
 

References

  • 《大话设计模式》

欢迎关注公众号
​​​​​​在这里插入图片描述

症状 假定您启用的计算机正在运行 Windows Server 2008 R2 中的 Hyper-V 角色。启用 Hyper-V 角色后重新启动计算机。但是,在重新启动操作过程中收到下面的 Stop 错误消息: 停止 0x0000007E (ffffffffc0000096、 parameter2、 parameter3、 parameter4 SYSTEM_THREAD_EXCEPTION_NOT_HANDLED 备注 这些 Stop 错误消息中的参数可能会因实际配置的不同而不同。 停止错误的症状可能会因计算机的系统故障选项的不同而不同。例如,出现停止错误时,可能会重新启动计算机。 回到顶端 | 提供反馈 原因 发生此问题是因为系统使用处理器支持 C 状态。但是,C stateis 不支持由 Hyper-V。 回到顶端 | 提供反馈 解决方案 若要解决此问题,请按照下列步骤操作: 禁用处理器虚拟化在 BIOS 中。 正常启动计算机。 应用此修补程序,然后重新启动计算机。 重新启用 BIOS 中,虚拟化的处理器。 启用处理器虚拟化和 BIOS 启用 Hyper-V 角色中。 热修复补丁程序信息 重要 Windows Vista 和 Windows Server 2008 的修补程序包含在相同的程序包中。但是,这些产品中的只有一个可能"热修复程序请求"页上列出。若要请求适用于 Windows Vista 和 Windows Server 2008 的修复程序包,只需选择该页面列出的产品。 可以从 Microsoft 获得支持的热修复补丁程序。但是,此修补程序仅能用于解决本文中描述的问题。此修补程序仅适用于遇到本文所述问题的系统。此修补程序可能会接受进一步的测试。因此,如果这个问题没有对您造成严重的影响,我们建议您等待包含此修复程序的下一个软件更新。 如果此修补程序可以下载,则此知识库文章顶部会出现"提供修补程序下载"部分。如果未显示此节,请联系 Microsoft 客户服务和支持,以获取此修复程序。 注意如果出现其他问题或需要任何故障诊断,您可能需要创建单独的服务请求。其他支持问题和事项,不适合于此特定的修补程序将收取照常收取支持费用。Microsoft 客户服务和支持电话号码,或创建单独的服务请求的完整列表,请访问下面的 Microsoft Web 站点: http://support.microsoft.com/contactus/?ws=support注意"可用的热修补程序下载"表格显示此热修复补丁程序适用的语言。如果您看不到您的语言,这是因为热修复补丁程序不适用于该语言。 先决条件 基于 Windows Server 2008 的计算机无需先决条件。 重新启动要求 在应用此修补程序后,您必须重新启动计算机。 修补程序替换信息 此修补程序不替代任何其他修补程序。 文件信息 此修复程序的全球版本具有的文件属性 (或更新的文件属性) 下表中列出。协调世界时 (UTC) 中列出了这些文件的日期和时间。当您查看文件信息时,它已转换为当地时间。要了解 UTC 与本地时间之间的时差,请在控制面板中的日期和时间项中使用时区选项卡。 Windows Server 2008 R2,基于 x64 版本 文件的名称 文件版本 文件大小 日期 时间 平台 Ntoskrnl.exe 6.1.7600.20510 5,511,256 2009 年 8 月 20 日 06:28 x64 Ntkrnlpa.exe 6.1.7600.20510 3,954,760 2009 年 8 月 20 日 05:54 不适用 Ntoskrnl.exe 6.1.7600.20510 3,899,480 2009 年 8 月 20 日 05:54 不适用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值