模版与策略模式

news2025/2/26 3:36:40

一,怎么选择

如果需要固定的执行流程,选模版

如果不需要固定的执行流程,只需要对一个方法做具体抽象,选策略

参考文章:

常用设计模式汇总,告诉你如何学习设计模式

二,常用写法

子类 extends absClass implements businiessInterface

absClass = absClass impements strategyInterface

样例与详细分析

public class ECCBMS195ServiceImpl extends AbstractBmsService implements ECCBMS195Service {
public abstract class AbstractBmsService implements BmsService {

一,策略接口

方法1:抽象类实现
方法2:子类实现,标识策略对象。后续工厂模式有用

public interface strategyInterface {

    boolean execute(EccMessageReqVO eccMessageReqVO) throws Exception;

    BmsServiceEnum getType();
}

二,抽象类

absClass

@Override
@Transactional
public boolean execute(EccMessageReqVO eccMessageReqVO) throws Exception {
    this.process(eccMessageReqVO);
    return true;
}

public abstract void process(EccMessageReqVO eccMessageReqVO) throws Exception;

三,业务接口 businiessInterface

public interface EccBms111Service {

    void bms111Execute(ReqEccBms111VO reqEccBms110VO) throws Exception;

}

四,子类

1,实现业务接口逻辑businiessInterface

public void bms111Execute(ReqEccBms111VO reqEccBms111VO) throws Exception {}

2,实现抽象方法 process。且抽象接口中,调用具体业务接口

public void process(EccMessageReqVO eccMessageReqVO) throws Exception {

this.bms111Execute(reqEccBms111VO);

}

3,实现枚举接口,标识自身策略对象类型

@Override
public BmsServiceEnum getType() {
    return BmsServiceEnum.ECC_BMS111;
}

5,工厂模式

初始化对象,提供获取具体对象接口

@Component
public class BmsServiceSelector implements InitializingBean {

    private static final Map<BmsServiceEnum, BmsService> serviceMap = new HashMap<>();

    @Resource
    private List<BmsService> EccServices;

    @Override
    public void afterPropertiesSet() throws Exception {
        for (BmsService service : EccServices) {
            serviceMap.put(service.getType(), service);
        }
    }

    public BmsService getService(BmsServiceEnum bmsServiceEnum) {
        if (null == bmsServiceEnum){
            throw new IllegalArgumentException("操作失败!");
        }
        return serviceMap.get(bmsServiceEnum);
    }
}

6,调用方

1,首先调用者,不同业务场景有自己的唯一标识,比如MQ下发时,不同的场景,MQ tag不同

根据tag - > 获取枚举 -》根据枚举 -〉 获取具体对象 - 》 用具体对象调用具体逻辑

2,调用执行逻辑是策略接口中方法,execute,这个接口有抽象类实现(非子类实现)

public interface BmsService {

    boolean execute(EccMessageReqVO eccMessageReqVO) throws Exception;

    BmsServiceEnum getType();

}
BmsServiceEnum bmsServiceEnum = BmsServiceEnum.fromValue(vo.getTags());
BmsService bmsService = bmsServiceSelector.getService(bmsServiceEnum);
if(Objects.isNull(bmsService)) return true;
vo.setEccServiceName(bmsServiceEnum.getName());
bmsService.execute(vo);

 疑问:如果不在BmsService中定义,删除,直接在抽象类中写个,普通的方法execute(即模版方法),有问题吗?

你看下有问题吗,报错了。调用者获取的是策略接口对象BmsService,是这个接口调用的。

再次体现,针对接口编程,非实现类编程。

 为什么有此一问呢?是不是想到了文章中这里,策略模式中定义Context,里面定义了抽象类,

private penguin _penguin;

然后直接根据抽象类对象,调用抽象类中抽象接口与普通接口。

违背了设计原则:依赖接口,非依赖具体类。

public class behaviorContext {
    private penguin _penguin;

    public behaviorContext(penguin newPenguin) {
        _penguin = newPenguin;
    }
    public void setPenguin(penguin newPenguin) {
        _penguin = newPenguin;
    }
    public void everyDay() {
        _penguin.eating();
        _penguin.sleeping();
        _penguin.beating();
    }
}

 实际使用中,会这样用吗,依赖抽象类。见过如下

场景:不同业务场景,导入excel,读取excel数据,并返回不同场景的对象(用通配符T)

public class BatchVehicleInfoController {

    private final ExcelUploadDataService<VehicleCoreExcel> vehicleCoreDataExcelService;
}
public abstract class ExcelUploadDataService<T> {


    /**
     * excel 读取含表头
     *
     * @param excelInputStream
     * @return
     */
    public ExcelReadResult<T> readWithHead(final InputStream excelInputStream, final Class<T> clazz) {}

}

三,这一波下来用了什么设计模式

哪一波?上文【常用写法】

子类 extends absClass implements businiessInterface

absClass = absClass impements strategyInterface

模版

抽象类中定义了模版方法execute(只有一个行为process),模版方法中,调用了抽象接口 process。

抽象类 + 模版方法 + 抽象接口(子类实现),根据这三点可以理解为模版模式

public boolean execute(EccMessageReqVO eccMessageReqVO) throws Exception { this.process(eccMessageReqVO); return true; }

策略

抽象类 + 抽象接口,可以理解为策略模式。这也是策略的一般格式。

二者异同

好像与模版模式,一样,那最大的不同是什么

我认为是调用者,获取对象的方式不同

模版模式,每一个场景对象直接new的。参考这篇文档

常用设计模式汇总,告诉你如何学习设计模式

如下

public class test {
    public static void main(String[] args) {
        System.out.println("littlePenguin:");
        littlePenguin penguin1 = new littlePenguin();
        penguin1.everyDay();
        System.out.println("middlePenguin:");
        middlePenguin penguin2 = new middlePenguin();
        penguin2.everyDay();
        System.out.println("bigPenguin:");
        bigPenguin penguin3 = new bigPenguin();
        penguin3.everyDay();
    }
}

模版模式,优化了调用者对象的创建方式

文章描述如下

这里就是策略模式的重点,我们再看一下策略模式的定义“我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象”,那么该contex对象如下:

public class behaviorContext {
    private penguin _penguin;

    public behaviorContext(penguin newPenguin) {
        _penguin = newPenguin;
    }
    public void setPenguin(penguin newPenguin) {
        _penguin = newPenguin;
    }
    public void everyDay() {
        _penguin.eating();
        _penguin.sleeping();
        _penguin.beating();
    }
}

最后看调用方式:

public class test {
    public static void main(String[] args) {
        behaviorContext behavior = new behaviorContext(new littlePenguin());
        behavior.everyDay();

        behavior.setPenguin(new middlePenguin());
        behavior.everyDay();

        behavior.setPenguin(new bigPenguin());
        behavior.everyDay();
    }
}

有何感想: 上面强调了两个对象

策略的对象 + context对象

你看最后调用的时候,还是new了,对应和模版模式相同。

只是包了一层,方法的真正的调用者不同

模版:new的具体对象直接调用

    littlePenguin penguin1 = new littlePenguin();
        penguin1.everyDay();

策略:抽象对象调用

把调用者对象包了一下,且这个对象是一个抽象的

private penguin _penguin;

调用者还是对象,是不过这个对象不是new的具体对象,是一个抽象对象

这也体现了设计原则:针对接口编程,不要针对实现编程

    public void everyDay() {
        _penguin.eating();
        _penguin.sleeping();
        _penguin.beating();
    }

那context对象的作用是什么?

再看下概念:一个行为随着策略对象改变而改变的context对象

总体来看,还是创建对象,并封装了一个调用具体逻辑的方法

public void everyDay() {
        _penguin.eating();
        _penguin.sleeping();
        _penguin.beating();
    }

但是我觉得封装方法不是重点,封装的方法,可以看作就一个抽象方法 _penguin.beating();

它的作用还是,提供了一个创建对象的入口。

一句话,它做的工厂模式的事

工厂

上面第三点,完全体现了,工厂模式

四,总结

现在回头看,模版与策略主要区别

1,模版有一套固定行为,策略无

2,策略封装了,对象的创建与获取。像是一个不那么完整的工厂模式(对比上面第5点)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1841837.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

天池人脸识别项目复现

1 项目背景 #c 概述 项目的目的 图像分类是整个计算机视觉领域中最基础的任务&#xff0c;也是最重要的任务之⼀&#xff0c;最适合拿来进⾏学习实践。为了让新⼿们能够⼀次性体验⼀个⼯业级别的图像分类任务的完整流程&#xff0c;本次我们选择带领⼤家完成⼀个对图片中⼈脸进…

《计算机组成原理》(学习笔记)(王道)

目录 一、计算机系统概述 *1.1 计算机发展历程 *1.1.1 计算机硬件的发展 *1.1.2 计算机软件的发展 1.2 计算机系统层次结构 1.2.1 计算机系统的组成 1.2.2 计算机硬件的基本组成 冯诺依曼体系结构特点&#xff08;6&#xff09;&#xff1a; 1.2.3 计算机软件的分类 …

RAG 与微调在大模型应用中如何抉择

随着大型语言模型热度的不断升温&#xff0c;越来越多的开发者和企业投身于基于这些大模型的应用程序开发中。然而&#xff0c;面对预训练基座模型未能达到预期的表现时&#xff0c;如何提升应用程序的性能就成为了一个迫在眉睫的问题。我们终将会问自己&#xff1a;为了优化结…

常用的Java日志框架:Log4j、SLF4J和Logback

日志是软件开发中不可或缺的一部分&#xff0c;它有助于记录应用程序的运行状态、调试问题和监控系统。Java中有多个流行的日志框架&#xff0c;如Log4j、SLF4J和Logback。 一、Log4j 1.1 什么是Log4j&#xff1f; Log4j是Apache基金会开发的一个开源日志框架&#xff0c;它…

【无线传感网】LEACH路由算法

1、LEACH路由算法简介 LEACH协议,全称是“低功耗自适应集簇分层型协议” (Low Energy Adaptive Clustering Hierarchy),是一种无线传感器网络路由协议。基于LEACH协议的算法,称为LEACH算法。 2、LEACH路由算法的基本思想 LEACH路由协议与以往的路由协议的不同之处在于其改变…

JavaSE 面向对象程序设计 正则表达式

正则表达式 正则表达式&#xff08;Regular Expression&#xff0c;简称Regex&#xff09;是用于匹配文本中模式的字符串表达式。它由普通字符&#xff08;例如字母、数字&#xff09;和特殊字符&#xff08;称为元字符&#xff09;组成&#xff0c;可以非常灵活地定义搜索模式…

【计算机网络仿真实验-实验3.1、3.2】交换路由综合实验

实验3.1 交换路由综合实验——作业1 一、实验目的 运用实验二&#xff08;可前往博主首页计算机网络专栏下查看&#xff09;中学到的知识&#xff0c;将这个图中的PC机连接起来组网并分析&#xff0c;本篇涉及代码以截图展示&#xff0c;过于简单的代码及操作不再详细介绍&…

数据分析第三讲:numpy的应用入门(二)

NumPy的应用&#xff08;二&#xff09; 数组对象的方法 获取描述统计信息 描述统计信息主要包括数据的集中趋势、离散程度和频数分析等&#xff0c;其中集中趋势主要看均值和中位数&#xff0c;离散程度可以看极值、方差、标准差等&#xff0c;详细的内容大家可以阅读《统计…

使用事件日志识别常见 Windows 错误

事件查看器&#xff0c;一个标准的诊断工具&#xff0c;嵌入在Windows操作系统&#xff0c;记录了所有的系统事件&#xff0c;该日志捕获有关硬件问题、软件中断和整体系统行为的详细信息。通过分析这些日志&#xff0c;管理员可以查明系统错误和运行时错误的根本原因。了解如何…

如何成为沟通高手,读懂人心的心理学

一、教程描述 人际关系和沟通能力是闯荡社会的重要资本&#xff0c;懂心理让你看透他人的心思&#xff0c;读懂人心让人占尽优势&#xff0c;有效沟通让你提高效率&#xff0c;知己知彼&#xff0c;谋定而后动&#xff0c;充分了解他人的心理是一个人立足于职场和社交场的基础…

SYD881X读取GATT VALUE的长度

SYD881X读取GATT VALUE的长度 现在具体遇到这样一个需要&#xff0c;机器生产后要更新profile&#xff0c;这个只能够通过升级4K来做&#xff0c;但是需要知道profile是否改变了&#xff0c;这个就要知道profile是否改变来决定是否要升级&#xff0c;这里的做法是增加一个函数&…

可以免费领取tokens的大模型服务

本文更新时间&#xff1a;2024年6月20日 豆包大模型 “亲爱的客户&#xff0c;模型提供方将在5月15日至8月30日期间&#xff0c;为您提供一次独特的机会&#xff0c;即高达5亿tokens的免费权益。这是我们对您长期支持的感谢&#xff0c;也是对未来合作的期待。” 在8月30日之…

手机网站制作软件是哪些

手机网站制作软件是一种用于设计、开发和创建适用于移动设备的网站的软件工具。随着移动互联网时代的到来&#xff0c;越来越多的用户开始使用手机浏览网页和进行在线交流&#xff0c;因此&#xff0c;手机网站制作软件也逐渐成为了市场上的热门工具。 1. Adobe Dreamweaver&am…

计算机组成原理(Wrong Question)

目录 一、计算机系统概述 *1.1 计算机发展历程 1.2 计算机系统层次结构 1.3 计算机的性能指标 二、 数据的表示和运算 2.1 数制和编码 2.2 运算方法和运算电路 2.3 浮点数的表示与运算 三、存储系统 3.1 存储器概述 3.2 主存储器 3.3 主存储器与CPU的连接 3.4 外部…

Springboot集成Mybatisplus过程

这里写目录标题 背景步骤明确标准实操过程创建好数据库&#xff0c;命名好&#xff08;这里会考察一个命名规范&#xff09;&#xff0c;表的命名&#xff0c;中间使用下划线隔离开。使用idea创建Springboot项目&#xff08;注意版本问题&#xff09;使用插件生成代码常用代码p…

下载mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar操作教程

1、下载地址&#xff1a;MySQL :: Download MySQL Community Server (Archived Versions) 2、截图如下

Nvidia Isaac Sim 入门教程 2024(3)图形界面

Isaac Sim 基本使用 版权信息 Copyright 2023-2024 Herman YeAuromix. All rights reserved.This course and all of its associated content, including but not limited to text, images, videos, and any other materials, are protected by copyright law. The author …

产品经理方法论

1、用户体验 5 要素 1&#xff0c;表现层是你拿到一个产品以后&#xff0c;视觉表现&#xff0c;配色&#xff0c;布局&#xff0c;排版等等 2&#xff0c;框架层&#xff0c;是交互层面的东西&#xff0c;比如&#xff0c;操作情况&#xff0c;刷新&#xff0c;页面跳转&…

android 在线程中更新界面

在Android中&#xff0c;你不能直接从子线程中更新UI&#xff0c;因为这会导致应用崩溃。你需要使用Handler或runOnUiThread()来更新UI。 使用Handler 以下是如何使用Handler在子线程中更新UI的示例&#xff1a; 1. 创建Handler实例&#xff1a; import android.os.Bundle;…

肩背筋膜炎怎么治疗最有效

肩背筋膜炎是一种常见的肌肉骨骼疾病&#xff0c;其症状主要包括&#xff1a;肩背区域疼痛&#xff1a;由于筋膜组织受到损伤&#xff0c;肩背部位会出现明显的疼痛&#xff0c;疼痛可能会放射到周围的其他部位&#xff0c;严重时会影响睡眠和休息。肌肉紧张和僵硬&#xff1a;…