设计模式② :交给子类

文章目录

  • 一、前言
  • 二、Template Method 模式
    • 1. 介绍
    • 2. 应用
    • 3. 总结
  • 三、Factory Method 模式
    • 1. 介绍
    • 2. 应用
    • 3. 总结
  • 参考内容

一、前言

有时候不想动脑子,就懒得看源码又不像浪费时间所以会看看书,但是又记不住,所以决定开始写"抄书"系列。本系列大部分内容都是来源于《 图解设计模式》(【日】结城浩 著),内容仅用于个人学习记录,可随意转载。

二、Template Method 模式

Template Method 模式 :将具体处理交给子类

1. 介绍

在父类中定义处理流程框架,在子类中实现具体处理的模式就称为 Template Method 模式。

在 Template Method 模式 中登场的角色:

  • AbstractClass(抽象类):AbstractClass 角色不仅负责实现模板方法,还负责声明在模板方法中所使用到的抽象方法。这些抽象方法由子类ConcreteClass角色负责实现。
  • ConcreteClass (具体类):该角色负责具体实现AbstractClass角色中定义的抽象方法。

类图如下, 抽象模板类会提供两个 methodA 、 methodB 两个抽象方法供子类实现,同时自身实现一个模板方法 templateMethod。在 templateMethod 方法中定义程序的行为,但行为的具体内容则是由子类实现:

在这里插入图片描述


Demo 如下:

	public abstract class AbstractClass {// 定义两个由子类实现的方法protected abstract void methodA();// 定义两个由子类实现的方法protected abstract void methodB();// 模板方法,在合适的场景可以将该方法定义为 final。// 模板类通过该方法定义了整个程序的行为,如下行为为:先调用 methodA 再调用 methodB// 对于子类则只需要关注 methodA 和 methodB 的具体实现,而不需要关注整个程序的行为。public void templateMethod() {methodA();methodB();}}// 子类只需要关注抽象方法的实现,而不需要关注整个调用过程public class StudentClass extends AbstractClass {@Overridepublic void methodA() {System.out.println("StudentClass.methodA");}@Overridepublic void methodB() {System.out.println("StudentClass.methodB");}}public class TeacherClass extends AbstractClass {@Overridepublic void methodA() {System.out.println("TeacherClass.methodA");}@Overridepublic void methodB() {System.out.println("TeacherClass.methodB");}}

2. 应用

Spring模板方法模式实质是模板方法模式和回调模式的结合,是Template Method不需要继承的另一种实现方式,如 JdbcTemplate、RedisTeplate、MongoTemplate 等。

这里我们以 JdbcTemplate为例,当我们调用 JdbcTemplate#execute 执行 Sql 时,JdbcTemplate#execute 流程是 DB 连接、Sql 执行、DB 释放,而我们实际只编写了Sql 部分,如下(下面代码仅作演示,真实代码并非如下)。

	private <T> T execute(String sql){// 1. 获取DB 连接以及其他预处理doDbConnect();// 2. Sql 执行executeSql(sql);// 3. 释放资源releaseDbConnection();}

可以看出 JdbcTemplate#execute 作为一个 Template Method 通过完成了 DB 连接与释放的功能。但实际上 Spring几乎所有的外接扩展都采用回调模式模式来执行。如下, 通过 callback 回调来执行具体的业务逻辑:

    public final Object execute(StatementCallback callback){    Connection con=null;    Statement stmt=null;    try {    con=getConnection();    stmt=con.createStatement();    Object retValue=callback.doWithStatement(stmt);    return retValue;    } catchSQLException e){    ...    } finally{    closeStatement(stmt);    releaseConnection(con);    }    }  

JDBC的抽象和对Hibernate的集成,都采用了一种理念或者处理方式,那就是模板方法模式与相应的Callback接口相结合。



个人使用:该部分内容是写给自己看的,帮助自身理解,因此就不交代项目背景了,读者请自行忽略(◐ˍ◑)

  • 项目A中,需要根据通道的不同构建不同的数据集,便使用了如下的模板模式,不同的通道实现各自的模板类,其中 DataHead 和 DataDetail 可以通过继承的方式进行各个通道的数据扩展。通过 DataTemplate#getFinalData 获取最终的数据集。

    // 抽象模板方法,供不同通道的子类实现
    public abstract class DataTemplate {/*** 获取头数据* @return*/protected abstract DataHead getDataHead();/*** 获取详细数据* @return*/protected abstract List<DataDetail> getDataDetail();/*** 获取最终的数据集* @return*/public FinalData getFinalData() {final FinalData finalData = new FinalData();finalData.setDataHead(getDataHead());finalData.setDataDetailList(getDataDetail());return finalData;}
    }
    
  1. 项目B中,需要对客户资料进行解析,资料固定是一个 PDF、一个 Excel 文件,需要对两个文件中的数据解析并汇总处理,而可能存在的情况是PDF 和 Excel 存在多套格式。即可以定义出来一个 FileTemplate ,不同格式的 PDF 和 Excel 实现不同的 FileTemplate ,最终完成多种模板格式的解析(可以通过策略模式对每一种不同的格式的文件实现单独的解析策略,进一步解耦)

    public abstract class FileTemplate {/*** 获取头数据* @return*/protected abstract PdfData getPdfData();/*** 获取详细数据* @return*/protected abstract ExcelData getExcelData();/*** 获取最终的数据集* @return*/public FileData getFinalData() {final FileData finalData = new FileData();finalData.setPdfData(getPdfData());finalData.setExcelData(getExcelData());return finalData;}
    }
    

3. 总结

在 Template Method 模式中,可以使用继承(实现)改变程序的行为。这是因为 Template Method 模式在父类中定义程序行为的框架,在子类中决定具体的处理。在该模式中,处理的流程被定义在父类中,而具体的处理则交给了子类。

在 Strategy 模式中,可以使用委托改变程序的行为。与 Template Method 模式中改变部分程序行为不同的是, Strategy 模式用于替换整个算法。


相关设计模式:

  • Factory Method 模式:Factory Method 模式是将 Template Method 模式用于生成实例的一个典型例子。
  • Strategy 模式:在 Template Method 模式中,可以使用继承(实现)改变程序的行为。这是因为 Template Method 模式在父类中定义程序行为的框架,在子类中决定具体的处理。在该模式中,处理的流程被定义在父类中,而具体的处理则交给了子类。而在 Strategy 模式中,他可以使用委托改变程序的行为。与 Template Method 中改变部分程序行为不同的是,Strategy 模式用于替换整个算法

三、Factory Method 模式

Factory Method 模式 :将实例的生成交给子类。

1. 介绍

Template Method 模式在父类中定义程序行为的框架,在子类中决定具体的处理。如果将该模式用于生成实例,那么他将演变成 Factory Method 模式。在该模式中,父类决定实例的生成方式,但并不决定所要生成的具体的类,具体的处理全部交给子类负责。这样就可以将生成实例的框架和实际负责生成实例的类解耦。


Factory Method 模式中登场的角色

  • Product (产品):Product 属于框架这一方,是一个抽象类。它定义了在 Factory Method 模式中生成的那些实例所持有的接口 (API),但具体的处理则由子类角色决定。
  • Creator (创建者):Creator 属于框架这一方,它是负责生成 Product 角色的抽象类,但具体的处理规则由子类角色决定。Creator 角色对于实际负责生成实例的ConcreteCreator角色一无所知,它唯一知道的就是只要调用 Product 角色和生成实例的方法就可以生成 Product 的实例。
  • ConcreteProduct (具体的产品):ConcreteProduct 属于具体的加工者一方,它决定了具体的产品。
  • ConcreteCreator(具体的创建者):ConcreteCreator 属于具体的加工者一方,它负责生产具体的产品。

类图如下:我们可以得知父类(框架)这一方面的角色的关系与子类(具体加工)这一方面的角色关系是平行的。这里Creator 定义了 create 方法用于创建(生产) Product 实例,同时 factoryMethod 则是该工厂类的其他工厂方法,具体需要根据业务去定义。

在这里插入图片描述


Demo 如下:

	public abstract class Creator {// create 方法用于创建 具体 Product,并可以执行其他逻辑,如 调用registerProduct方法实现注册功能等(具体看业务需求)public final Product create(){final Product product = createProduct();registerProduct(product);return product;}// 下面是 factoryMethod 方法// 使用 createProduct 创建 Product,目的是父类与子类解耦。protected abstract Product createProduct();// 注册产品protected abstract void registerProduct(Product product);}public abstract class Product {// 随意定义的两个 方法public abstract void methodA();public abstract void methodB();}public class ConcreteCreator extends Creator{// 实现 factoryMethod, 根据业务需要可以有不同的实现@Overrideprotected Product createProduct() {return new ConcreteProduct();}// 根据业务需要进行实现,这里随意调用了 Product 的两个方法@Overrideprotected void registerProduct(Product product) {product.methodA();product.methodB();}}public class ConcreteProduct extends Product {@Overridepublic void methodA() {System.out.println("ConcreteProduct.methodA");}@Overridepublic void methodB() {System.out.println("ConcreteProduct.methodB");}}// 用于测试的 Main 方法public class FactoryMethodMain {public static void main(String[] args) {// 实际场景下  Creator 应该有多个实现类,而在这种情况下可以使用工厂模式或简单工厂模式来获取 Creator 实例。Creator creator = new ConcreteCreator();// 调用模板方法创建具体实例final Product product = creator.create();// TODO : do something}}

2. 应用

  • Spring 框架支持通过 factory-bean 和 factory-method 属性的方式来指定工厂方法来创建Bean。如下指定 DesignConfig#designDemo 的方法来创建 DesignDemo 并注册到容器中,在指定的 factory-method 方法中可以实现自定义的逻辑:

    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="designConfig" class="com.kingfish.pojo.config.DesignConfig"/><bean id="designDemo" class="com.kingfish.pojo.DesignDemo" factory-bean="designConfig" factory-method="designDemo"/></beans>
    


个人使用:该部分内容是写给自己看的,帮助自身理解,因此就不交代项目背景了,读者请自行忽略(◐ˍ◑)

  • 项目A中,不同的 Region 都会获取相同的数据,但数据来源以及拼接不同,因此计划在服务启动或在其他触发条件下,生成一个 RegionContent 类,可以作为上下文或者其他的数据,不同 Region 进行具体实现,根据 Region 的不同加载不同的 RegionContent 实例来获取对应的全局数据。如下:

    /*** 顶层定义一个 Creator 接口*/
    public interface ContextCreator {RegionContent createContext();
    }// 定义一个 Region Creator 的抽象类,用于创建 RegionContent 
    public abstract class RegionContentCreator implements ContextCreator {@Overridepublic final RegionContent createContext() {final RegionContent regionContent = doCreateContent();postProcess(regionContent);return regionContent;}// 创建方法protected abstract RegionContent doCreateContent();// 后置处理,在 RegionContent 创建的后置处理 - 需要的话可以实现protected abstract void postProcess(RegionContent regionContent);
    }// SH  Region的实现
    @Slf4j
    public class ShRegionContentCreator extends RegionContentCreator {@Overrideprotected RegionContent doCreateContent() {return new ShRegionContext();}@Overrideprotected void postProcess(RegionContent regionContent) {log.info("[region 后期处理][regionContext = {}]", regionContent);}
    }// RegionContent 接口定义
    public interface RegionContent {/*** 返回 region 标识* @return*/String getRegion();/*** 获取关区内容* @return 懒得定义实现类,所以返回 Object*/Object getContent();
    }// SH RegionContent 的实现
    public class ShRegionContext implements RegionContent {@Overridepublic String getRegion() {// 应该用全局变量或者枚举return "sh";}@Overridepublic Object getContent() {// 随便返回return "这里是 SH Region 的 Content";}
    }@Slf4j
    public class DemoMain {public static void main(String[] args) {// 创建 RegionContent 。实际业务会有多个 RegionContentCreator, 可以根据环境或者参数加载RegionContentCreator regionContentCreator = new ShRegionContentCreator();final RegionContent content = regionContentCreator.createContext();// 随便打印log.info("region = {}, regionContent = {}", content.getRegion(), content.getContent());}
    }
    

3. 总结

相关的设计模式:

  • Template Method 模式:Factory Method 模式是 Template Method 的典型应用
  • Singleton 模式:多数情况下 Singleton 模式用于扮演 Creator 角色 或者 ConcreteCreator 橘色的类,这是因为在程序中没有必要存在多个Creator 或 ConcreteCreator 角色的实例。
  • Composite 模式:有时候可以将 Composite 模式用于 Product 或 ConcreteProduct 角色。
  • Iterator 模式:有时在 Iterator 模式中使用 iterator 方法生成 Iterator 的实例时会使用 Factory Method。

参考内容

https://mp.weixin.qq.com/s/JUV4cnE_HqRMFriKMHk0Ug

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营day6|242.有效的字母异位词、349.两个数组的交集、202.快乐数

哈希表理论基础 建议&#xff1a;大家要了解哈希表的内部实现原理&#xff0c;哈希函数&#xff0c;哈希碰撞&#xff0c;以及常见哈希表的区别&#xff0c;数组&#xff0c;set 和map。 什么时候想到用哈希法&#xff0c;当我们遇到了要快速判断一个元素是否出现集合里的时…

【React系列】React中的CSS

本文来自#React系列教程&#xff1a;https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg5MDAzNzkwNA&actiongetalbum&album_id1566025152667107329) 一. React中的css方案 1.1. react 中的 css 事实上&#xff0c;css 一直是 React 的痛点&#xff0c;也是被很多开发…

自动生成表结构screw

采用的组件 screw 操作流程&#xff1a; 1、新建springboot 项目 2、引入相关的依赖 <!-- screw核心 --><dependency><groupId>cn.smallbun.screw</groupId><artifactId>screw-core</artifactId><version>1.0.4</version><…

2023 年精选:每个 DevOps 团队都应该了解的 5 种微服务设计模式

微服务彻底改变了应用程序开发世界&#xff0c;将大型整体系统分解为更小、更易于管理的组件。这种架构风格的特点是独立、松散耦合的服务&#xff0c;带来了从可扩展性、模块化到更高的灵活性等众多优势。 DevOps 团队如何最好地利用这种方法来实现最高效率&#xff1f;答案在…

分布式基础概念

分布式基础概念 1 微服务 微服务架构风格&#xff0c;就像是把一个单独的应用程序开发为一套小服务&#xff0c;每个小服务运行在自己的进程中&#xff0c;并使用轻量级机制通信&#xff0c;通常是HTTP API。这些服务围绕业务能力来构建&#xff0c;并通过完全自动化部署机制…

ElasticSearch 集群搭建与状态监控cerebro

单机的elasticsearch做数据存储&#xff0c;必然面临两个问题:海量数据存储问题、单点故障问题。为了解决存储能力上上限问题就可以用到集群部署。 海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard)&#xff0c;存储到多个节点单点故障问题:将分片数据在不同节点备份 (r…

[每周一更]-(第82期):选购NAS中重要角色RAID

网络附加存储&#xff08;NAS&#xff09;在现代数字生活中扮演着至关重要的角色&#xff0c;而对于NAS的选择中&#xff0c;关注RAID的重要性更是不可忽视的。 数据存储和安全越来越受关注&#xff1b; 为什么要使用NAS&#xff1f; 集中式存储&#xff1a; NAS提供了一个集中…

【计算机病毒传播模型】报告:区块链在车联网中的应用

区块链在车联网中的应用 写在最前面题目 - 26 车联网安全汇报演讲稿-删减2后&#xff0c;最终版&#xff08;1469字版本&#xff09;汇报演讲稿-删减1后&#xff08;2555字版本&#xff09;汇报演讲稿-删减前&#xff08;3677字版本&#xff09;1 概述1.1 车联网1.2 区块链1.3 …

Linux离线安装MySQL(rpm)

目录 下载安装包安装MySQL检测安装结果服务启停MySQL用户设置 下载安装包 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 下载全量包如&#xff1a;(mysql-8.1.0-1.el7.x86_64.rpm-bundle.tar) 解压&#xff1a;tar -xzvf mysql-8.1.0-1.el7.x86_64.…

Docker学习与应用(四)-容器数据卷

1、容器数据卷 1&#xff09;什么是容器数据卷 docker的理念回顾 将应用和环境打包成一个镜像&#xff01; 数据&#xff1f;如果数据都在容器中&#xff0c;那么我们容器删除&#xff0c;数据就会丢失&#xff01;需求&#xff1a;数据可以持久化 MySQL&#xff0c;容器删…

docker kingbase

docker kingbase run 命令 docker run -tid \ -e ENABLE_CIyes \ -e NEED_STARTyes \ -e DB_MODEoracle \ -e DB_USERkingbase \ -e DB_PASSWORD123456 \ --privileged \ -p 4321:54321 \ -v /home/admin/SoftWare/volume/kingbase/userdata/data:/home/kingbase/userdata/da…

IPv6路由协议---IPv6动态路由(OSPFv3-2)

OSPFv3特性 1.OSPFv3基于链路运行 OSPFv3不需要考虑是否配置在同一网段,只要在同一链路,就可以不配置IPv6全局地址而直接建立邻接关系来计算和传递路由信息。 OSPFv2版本是基于IP子网运行 (1)同一链路上的所有节点都必须处于同一个IP子网或网络内。 (2)邻居关系建立的…

Color Control

设计一个优秀的用户界面是一项艰巨的任务。特别是如果你想改变UI的颜色,调整所有元素可能需要花费大量时间。Color Control可以帮助你!在检查器中以可视化的方式将你的项目颜色定义为资源。Color Control为你提供了组件,当你编辑它们时,它们会自动更新你的UI元素。 颜色控制…

共识算法介绍

文章目录 共识算法Paxos 算法三种角色一致性提交算法prepare 阶段accept 阶段commit 阶段 CAP 定理BASE 理论Zookeeper 算法实现三类角色三个数据三种模式四种状态消息广播算法Leader选举算法 共识算法 Paxos 算法 Paxos 算法是莱斯利兰伯特(Leslie Lamport)1990 年提出的一种…

Nacos部署与应用指南

一、前言 Nacos&#xff08;前身为阿里巴巴的Nacos Config和Nacos Discovery&#xff09;是一款开源的分布式服务和配置管理平台&#xff0c;可以帮助开发者更轻松地构建、部署和管理微服务体系结构。本文将详细介绍如何部署Nacos以及如何在应用中使用它。 二、Nacos部署 2.1 …

机器人活动区域 - 华为OD统一考试

OD统一考试 题解: Java / Python / C++ 题目描述 现有一个机器人,可放置于 M x N 的网格中任意位置,每个网格包含一个非负整数编号,当相邻网格的数字编号差值的绝对值小于等于 1 时机器人可以在网格间移动。 问题: 求机器人可活动的最大范围对应的网格点数目。 说明: 网格…

js数组循环,当前循环完成后执行下次循环

前言 上图中&#xff0c;点击播放icon&#xff0c;图中左边地球视角会按照视角列表依次执行。u3D提供了api,但是我们如何保证在循环中依次执行。即第一次执行完成后&#xff0c;再走第二次循环。很多人的第一思路就是promise。对&#xff0c;不错&#xff0c;出发的思路是正确的…

Nougat:科学文档的OCR 使用记录

https://github.com/facebookresearch/nougat python环境需要在3.8以上 安装&#xff1a;pip install nougat-ocr 模型默认下载地址&#xff1a;/home/****/.cache/torch/hub/nougat-0.1.0-small 环境安装好之后默认使用cpu UserWarning: CUDA initialization: The NVIDIA dr…

【Java集合篇】HashMap的hash方法是如何实现的?

HashMap的hash方法是如何实现的? ✔️ 典型解析✔️ 拓展知识仓✔️ 使用&代替%运算✔️扰动计算 ✔️ 典型解析 hash 方法的功能是根据 Key 来定位这个K-V在链表数组中的位置的。也就是hash方法的输入应该是个Object类型的Key&#xff0c;输出应该是个int类型的数组下标。…

ConcurrentHashMap的原理分析学习

ConcurrentHashMap 的初步使用及场景 CHM 的使用 ConcurrentHashMap 是 J.U.C 包里面提供的一个线程安全并且高效的 HashMap&#xff0c;所以ConcurrentHashMap 在并发编程的场景中使用的频率比较高&#xff0c;那么这一节课我们就从ConcurrentHashMap 的使用上以及源码层面来…