详述java的设计模式(四)

news2024/11/26 16:52:14

 1.模板方法模式

模板方法模式是一种行为设计模式,它定义了一个操作中算法的骨架,将算法中不同的实现延迟到子类中。这个模式可以在不改变算法结构的前提下,使子类可以重新定义算法中的某些步骤,从而满足不同的需求。

模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码,使得子类可以集中于自己的行为的变化而不是系统整体的变化来设计的一种模式。

在模板方法模式中,超类通常定义一个模板方法,这个方法会在内部调用多个其他的抽象方法,子类需要实现这些抽象方法以定义自己的行为。这个模式可以非常好地应对开发中变化的需求,因为它允许在不改变算法结构的情况下,改变部分行为的实现方式。

假设我们要写一个文件读取器,它需要从文件中读取数据,并将数据转换成特定的格式。这个转换的过程可以由子类来实现,而读取文件的过程则是固定的,可以在父类中实现。以下是一个示例代码:

// 抽象文件读取器
public abstract class FileReader {
    // 模板方法
    public final void read() {
        open();
        readData();
        close();
    }
    
    // 打开文件
    protected void open() {
        System.out.println("打开文件");
    }
    
    // 读取文件数据,由子类实现
    protected abstract void readData();
    
    // 关闭文件
    protected void close() {
        System.out.println("关闭文件");
    }
}
// 文本文件读取器
public class TextFileReader extends FileReader {    
@Override    
protected void readData() {        
System.out.println("读取文本文件数据");    
}
}
// 图片文件读取器
public class ImageFileReader extends FileReader {
    @Override
    protected void readData() {
        System.out.println("读取图片文件数据");
    }
}

// 测试程序
public class Test {
    public static void main(String[] args) {
        // 使用文本文件读取器
        FileReader reader = new TextFileReader();
        reader.read();
        
        // 使用图片文件读取器
        reader = new ImageFileReader();
        reader.read();
    }
}

优缺点

模板方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

在模板方法模式中,有一个抽象类定义了一个模板方法,它给出了一个算法的骨架,而将具体实现推迟到子类中去实现。抽象类通常还定义了一些基本的操作,这些操作可以由子类直接使用,也可以由子类进一步扩展和改进。

模板方法模式的优点是:

将算法的框架和具体实现分离,使得实现更加灵活;
可以避免重复代码,减少代码冗余;
使得子类可以在不改变算法结构的情况下重定义算法的某些特定步骤。
模板方法模式的缺点是:

由于算法的框架是固定的,因此如果算法框架需要改变,那么需要修改抽象类的代码,这可能会导致一些潜在的风险;
由于算法的实现被延迟到子类中,因此子类的数目可能会增加,增加了系统的复杂度。

模板模式 vs 策略模式

我在选择模板模式和策略模式时,发现两者都可以完全满足我的需求,然后我到网上查阅了很多资料,希望能找到两种模式在技术选择时,能确定告诉我哪些情况需要选择哪种模式,说来惭愧,到现在我都没有找到,因为网上只告诉我两种实现姿势的区别,但是没有说明如何具体选型,下面我就把我收集的资料,觉得比较核心的部分列出来,给大家一些参考。

有人请向我解释模板方法模式和策略模式之间有什么区别?

据我可以告诉他们是99%相同 – 唯一的区别是模板方法模式具有抽象类作为基类,而战略类使用由每个具体战略类实现的接口。

然而,就客户而言,他们的消费方式完全一样 – 这是正确的吗?

两者的主要区别在于具体algorithm的select。

使用Template方法模式时,通过子类化模板在编译时发生。 每个子类通过实现模板的抽象方法提供了一个不同的具体algorithm。 当客户端调用模板的外部接口的方法时,模板根据需要调用其抽象方法(其内部接口)来调用algorithm。

相比之下, 策略模式允许在运行时通过遏制来selectalgorithm。 具体algorithm是通过单独的类或函数实现的,这些类或函数作为parameter passing给构造函数或构造方法。 为此参数select哪种algorithm会根据程序的状态或inputdynamic变化。

综上所述:

  • 模板方法模式:通过子类化 编译时间algorithmselect

  • 策略模式:通过遏制 运行时algorithmselect

上面是完全摘抄网上的区别说明,只看到实现姿势的区别,但是如果通过这个就能指导我去选型,我觉得还不够,下面这个可能会讲的更具体一点:

相似:

  • 策略和模板方法模式都可以用来满足开闭原则,使得软件模块在不改变代码的情况下易于扩展。

  • 两种模式都表示通用function与该function的详细实现的分离。不过,它们所提供的粒度有一些差异。

差异:

  • 在策略中,客户和策略之间的耦合更加松散,而在模板方法中,两个模块耦合得更紧密。

  • 在策略中,虽然抽象类也可以根据具体情况而使用,但大多使用一个接口,而不使用具体类,而在Template方法中大多使用抽象类或具体类,不使用接口。

  • 在Strategy模式中,类的整体行为一般用接口表示,另一方面,Template方法用于减less代码重复,样板代码在基本框架或抽象类中定义。 在Template Method中,甚至可以有一个具有默认实现的具体类。

  • 简而言之,您可以在策略模式中更改整个策略(algorithm),但是在Template模式中,只有一些事情发生变化(algorithm的一部分),而其余事件保持不变。 在Template Method中,不变步骤是在一个抽象基类中实现的,而变体步骤要么是默认的实现,要么根本就没有实现。 在Template方法中,组件devise器强制执行algorithm所需的步骤和步骤的sorting,但允许组件客户端扩展或replace某些步骤。

看到上面的总结,感觉还是没有解答我的疑问,最后再引用一段网上的区别解读:

模板模式:

  • 它基于inheritance。

  • 定义不能被子类改变的algorithm的骨架。只有某些操作可以在子类中重写。

  • 父类完全控制algorithm ,仅将具体的步骤与具体的类进行区分。

  • 绑定是在编译时完成的。

策略模式:

  • 它基于授权/组成。

  • 它通过修改方法的行为来改变对象的内容。

  • 它用于在algorithm族之间切换。

  • 它在运行时通过在运行时用其他algorithm完全replace一个algorithm来改变对象的行为。

  • 绑定在运行时完成。

对于有强迫症的我,没有找到问题的根源,总感觉哪里不对劲,我就说一下我对于两者区别的理解吧。说实话,两种设计模式,我也就看到在实现姿势上有所区别,至于说的策略模式要定义统一接口,模板模式不这样做等等,我不太赞同,因为我有时也会给模板模式定义一个通用接口。然后也有人说,策略模式需要定义一堆对象,模板模式就不需要,如果有10个不同的企鹅,模板模式不也是需要定义10个不同的企鹅类,然后再专门针对特定的方法去实现么?

所以说,这两种设计模式,我感觉还没有到非此即彼的划分,我就是怎么爽就怎么用,比如企鹅模式的“吃饭、睡觉、打豆豆”,我不需要固定的执行流程,比如只去打豆豆,只需要对一个方法做具体抽象,我愿意选择策略模式,因为这个我感觉会让我需要使用的对象,更清晰一些。如果我有固定的执行流程,比如“吃饭、睡觉、打豆豆”,我更愿意使用模板方法,可能是代码看多了,也看习惯了,更愿意用模板方法去规范代码固定的执行流程。

当然,我也可以将两者结合起来使用,比如我们可以用模板方法,去实现这3只企鹅,但是对于middlePenguin,可能有分为企鹅少年A、企鹅少年B、企鹅少年C,他们都喜欢隔壁的企鹅妹妹,但是喜欢的方式不同,有暗恋的,有直接表白的,还有霸道总裁的,我可以用策略模式,去指定他们对企鹅妹妹的表达方式。

生活实例

模板方法模式的应用在生活中比较常见。比如说,我们想要做一道鱼香肉丝这道菜。一般来说,做鱼香肉丝需要以下步骤:备料、切菜、调料、炒菜、出锅。这些步骤的顺序不能改变,否则就无法做出一道正宗的鱼香肉丝。

那么我们可以把这些步骤抽象出来,定义一个模板类,包含这些步骤的执行顺序。每个具体的鱼香肉丝厨师可以继承这个模板类,并实现自己的具体做法。比如有的厨师喜欢加一点葱姜蒜,有的厨师喜欢放些辣椒,有的厨师会在炒之前把肉片先用淀粉抓匀。这些实现细节都是在子类中完成的,而模板方法模式确保了步骤的执行顺序不变。

这样做的好处是,当我们想要改变鱼香肉丝的做法时,只需要修改对应的子类即可。比如我们想要把鱼香肉丝做成甜的,就可以新建一个继承模板类的子类,重新实现调料的步骤即可。模板方法模式让代码的扩展性更好,也使得我们更容易修改代码而不会影响到其他的部分。

2.适配器模式

适配器模式是一种结构型设计模式,它的主要作用是让原本不兼容的接口能够相互合作。

适配器模式的代码示例:

目标接口、源接口

public interface Target {
    void request();
}
public class Adaptee {    
void specificRequest() {        
System.out.println("执行源接口的方法");   
}
}

适配器

public class Adapter implements Target {

    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

使用

public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request();
    }
}

Adaptee假如是一个3.5mm的耳机插孔,Target是一个Type-C的耳机,Adapter就是一个转接头,将3.5mm的耳机插孔转换成Type-C的插孔。

描述

在上面的代码中,Target 接口是适配器希望实现的目标接口。Adaptee 类是已经存在的源接口,但是它的方法与 Target 接口不兼容。Adapter 类实现了 Target 接口,并在内部使用了 Adaptee 类来实现 request() 方法。通过使用 Adapter 类,客户端代码就可以调用 request() 方法,而不需要直接调用 specificRequest() 方法。

使用场景

1.已经存在的类的接口和需求不匹配。例如,你可以使用适配器模式来兼容旧的打印机,而无需更改客户端代码。

2.在一些类中使用第三方组件,这些组件的接口可能不符合系统设计标准,或者它们不提供必要的功能。适配器模式可以将这些组件的接口转换为系统所期望的接口,从而满足系统的需要。

3.需要使用已经存在的多个子类,但这些子类缺少某些共同的功能,这时适配器模式可以在不修改现有代码的情况下增加这些缺失的功能。

4.需要一个统一的输出格式来输出多个类的数据。这时,可以使用适配器模式将多个类的接口转换为统一的输出格式。

优缺点

类适配器
优点:可以根据需求重写Adaptee类的方法,使得Adapter的灵活性增强了。
缺点:有一定局限性。因为类适配器需要继承Target类,而Java是单继承机制,所以要求Adaptee类必须是接口。

对象适配器
优点:同一个Adapter可以把Adaptee类和他的子类都适配到目标接口。
缺点:需要重新定义Adaptee行为时,需要重新定义Adaptee的子类,并将适配器组合适配。

接口适配器
优点:可以灵活方便的选择性重写接口方法。
缺点:由于是匿名内部类的形式,所以不利于代码复用。

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

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

相关文章

【蓝桥杯嵌入式】STM32定时器的配置,解析预分频系数和重装载值与时钟频率的关系

🎊【蓝桥杯嵌入式】专题正在持续更新中,原理图解析✨,各模块分析✨以及历年真题讲解✨都在这儿哦,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 - 蓝…

vue3中前端处理不同数据结构的JSON

有时候,后端返回的JSON数据格式,是前端不需要的格式类型,这时,要么让后端修改,你要什么格式,那么让后端大哥哥给你返回什么格式。但是有时候不尽人意,后端大哥哥让你自己转换,此时就…

【javaScript面试题】2023前端最新版javaScript模块,高频24问

🥳博 主:初映CY的前说(前端领域) 🌞个人信条:想要变成得到,中间还有做到! 🤘本文核心:博主收集的关于javaScript的面试题 目录 一、2023javaScript面试题精选 1.js的数据类型…

Temporal Fusion Transformer (TFT) 各模块功能和代码解析(pytorch)

Temporal Fusion Transformer (TFT) 各模块功能和代码解析(pytorch) 文章目录Temporal Fusion Transformer (TFT) 各模块功能和代码解析(pytorch)GLU(Gated Linear Unit)模块GRN(Gated Residual Network)门控残差网络Transformer经典模块Add&Normalize模块Scaled Dot-Produ…

【Leetcode】【简单】704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解释: 9 出现…

HNU工训中心:数模转换实验报告

D 级任务:实验 74194 的仿真验证 1. 实验任务 任务:实验 74194 的仿真验证,掌握 Quartus 仿真的基本原则和常规步骤,记录移 位寄存器的数据读写,并描述仿真波形,结果分析并记录到实验报告。 实验实作 最终的电路图…

“探索未来:VR全景直播技术引领新媒体时代”

随着虚拟现实技术的不断发展,VR全景直播已经成为了越来越受欢迎的直播形式。VR全景直播可以让观众通过虚拟现实设备亲临直播现场,享受身临其境的观看体验。VR全景直播是什么? VR全景直播是虚拟现实技术和直播的结合。相对于传统直播&#xff…

SOLIDWORKS提升 SAE赛车队成绩

SOLIDWORKS Education Edition实施结果: ●将车队成绩提升至史上最高水平 ●使用仿真工具验证赛车设计 ●促进车队成员之间的交流 ●增强设计可视化试用及报价新罕布什尔大学是美国顶级研究机构之一。UNH 拥有多个学术部门、跨学科机构和研究中心,屹立在…

APP发布----HBuilder

pc端:桌面应用:electronjs–vasode web应用: 纯前端开发—vue、react等框架 混合开发 — php、jsp、asp App开发类型 原生开发: Jave – AndroidObject – iosc – 鸿蒙运行效率最高、开发复杂、页面一致性 web-app(…

新C++(12):位图与海量数据处理

"无关利弊或对错,勇气一直在"现在给你一道面试题:给40亿个不重复的无符号整数,没有任何排序。给出一个无符号整数,如何快速地判断,该数是否存在于40亿多个这样的无符号整数之中?唔……我想将这40亿个多数进行…

25- 卷积神经网络(CNN)原理 (TensorFlow系列) (深度学习)

知识要点 卷积神经网络的几个主要结构: 卷积层(Convolutions): Valid :不填充,也就是最终大小为卷积后的大小. Same:输出大小与原图大小一致,那么N ​变成了​N2P. padding-零填充. 池化层(Subsampli…

STM32HAL库1:认识时钟树(STM32F407)

目录 1.认识时钟树 1.1什么时钟 1.2认识时钟树 2.配置系统时钟 2.1系统适中的配置过程 2.2外设时钟使能和失能 2.3sys_stm32_clock_init函数(F407) 2.4SystemClock_Config函数(F407) [F1] [F4] 1.认识时钟树 1.1什么时钟 …

【禅道测试环境搭建及安装】Linux上的禅道安装教程,从环境搭建开始

目录 一、操作环境 二、安装VMware 三、安装FinalShell 四、在VMware里安装CentOS 1.前置:CentOS的下载 2.CentOS的安装 3.查看网络 五、用宿主机连接远程的虚拟机 六、禅道包的下载与CentOS配置的修改 七、上传项目包并安装禅道 一、操作环境 Windows 10…

Substrate 基础教程(Tutorials) -- 授权特定节点

五、授权特定节点 在添加可信节点中,您看到了如何使用一组已知的验证器节点构建一个简单的网络。该教程演示了一个简化版的许可网络(permissioned network)。在一个被许可的网络中,只有被授权的节点(authorized nodes…

STM32CubexMX与FreeRTOS学习

FreeRTOS结合MX软件开发,基础配置直接生成,我们只需要会操作即可,操作一些API函数,注意事项就是:头文件、二值信号量一开始就有、定时器需要打开并且配置周期 1-LED-EXTI 上下拉模式和触发模式不要选择错误 void HAL_…

Elasticsearch:如何在 Elastic 中实现图片相似度搜索

作者:Radovan Ondas 在本文章,我们将了解如何通过几个步骤在 Elastic 中实施相似图像搜索。 开始设置应用程序环境,然后导入 NLP 模型,最后完成为你的图像集生成嵌入。 Elastic 图像相似性搜索概览 >> 如何设置环境 第一步…

【11】linux命令每日分享——useradd添加用户

大家好,这里是sdust-vrlab,Linux是一种免费使用和自由传播的类UNIX操作系统,Linux的基本思想有两点:一切都是文件;每个文件都有确定的用途;linux涉及到IT行业的方方面面,在我们日常的学习中&…

网页全屏截图、在线截图API

在我们的数字时代,网页截图已经成为了一个非常常见的需求,无论是为了记录网页信息、保存重要信息或是与他人分享自己看到的内容,截图工具都是必不可少的。今天,我想向大家推荐一个非常好用的在线网页全屏截图工具,它的…

获取html元素相对屏幕的位置

1. 写在前面 Javascript 由三部分构成,ECMAScript,DOM和BOM。 ECMAScript(核心)   描述了JS的语法和基本对象 Bom:(browser object model);浏览器对象模型,提供一些属性和方法可以操作浏览器,浏览器可…

【spring】Spring Data --Spring Data JPA

Spring Data 的委托是为数据访问提供熟悉且符合 Spring 的编程模型,同时仍保留着相关数据存储的特​​殊特征。 它使使用数据访问技术、关系和非关系数据库、map-reduce 框架和基于云的数据服务变得容易。这是一个伞形项目,其中包含许多特定于给定数据库…