当系统接口要加入新方法时,我真后悔没有早点学学Java设计模式

news2024/12/24 9:43:29

假设系统中有一个接口,这个接口已经被10个实现类实现了,突然有一天,新的需求来了,其中5个实现类需要实现同一个方法。然后你就在接口中添加了这个方法的定义,想着一切都很完美。

当你在接口和其中5个实现类中加完这个方法后,一编译。不妙啊,另外那 5 个实现类报错了,没实现新加的这个方法。要知道,接口中的方法定义必须要在实现类中实现才行,缺一个都编译不过。

这时候你耳边突然响起了开发之初的老前辈跟你说的话:“这几个实现以后可能差距越来越大,接口中可能会加方法,注意留口子”。

图片

现在咋整

假设之前的接口是这样的,只有吃饭和喝水两个方法。

public interface IUser {

    /**
     * 吃饭啊
     */
    void eat();

    /**
     * 喝水啊
     */
    void drink();
}

现在有 5 个实现类厉害了,要加一个 play() 方法。

既然情况已经这样了,现在应该怎么处理。

破罐子破摔吧,走你

不管什么接口不接口的了,哪个实现类要加,就直接在那个实现类里加吧,接口还保持之前的样子不动,仍然只有吃饭和喝水两个方法,play 方法就直接加到 5 个实现类中。

public class UserOne implements IUser{

    @Override
    public void eat() {
        System.out.println("吃饭");
    }

    @Override
    public void drink() {
        System.out.println("喝水");
    }
    
    public void play() {
        System.out.println("玩儿");
    }
}

虽然可以实现,但是完全背离了当初设计接口的初衷,本来是照着五星级酒店盖的,结果盖了一层之后,上面的变茅草屋了。

从此以后,接口是接口,实现类是实现类,基本上也就没什么关系了。灵活性倒是出来了,以后想在哪个实现类加方法就直接加了。

图片

再加一个接口行不

还是有点儿追求吧,我新加一个接口行不行。之前的接口不动,新建一个接口,这个接口除了包含之前的两个方法外,再把 play 方法加进去。

这样一来,把需要实现 play 方法的单独在弄一个接口出来。就像下面这样 IUser是之前的接口。IUserExtend接口是新加的,加入了 play() 方法,需要实现 play() 方法的实现类改成实现新的IUserExtend接口,只改几个实现关系,改动不是很大嘛,心满意足了。

图片

但是好景不长啊,过了几天,又要加新方法了,假设是上图的 UserOne和 UserNine要增加方法,怎么办呢?

图片

假如上天再给我一次机会

假如上天再给我一次重来的机会,我会对自己说:“别瞎搞,看看设计模式吧”。

适配器模式

适配器模式可以通过创建一个适配器类,该适配器类实现接口并提供默认实现,然后已有的实现类可以继承适配器类而不是直接实现接口。这样,已有的实现类不需要修改,而只需要在需要覆盖新方法的实现类中实现新方法。

图片

不是要加个 play() 方法吗,没问题,直接在接口里加上。

public interface IUser {
    void eat();
    void drink();
    void play();
} 

适配器类很重要,它是一个中间适配层,是一个抽象类。之前不是实现类直接 implements 接口类吗,而现在适配器类 implements 接口类,而实现类 extends 适配器类。

在适配器类可以给每个方法一个默认实现,当然也可以什么都不干。

public abstract class UserAdapter implements IUser {
    @Override
    public void eat() {
        // 默认实现
    }

    @Override
    public void drink() {
        // 默认实现
    }

    @Override
    public void play() {
        // 默认实现
    }
}
public class UserNine extends UserAdapter {
    @Override
    public void eat() {
        System.out.println("吃饭");
    }

    @Override
    public void drink() {
        System.out.println("喝水");
    }

    @Override
    public void play() {
        System.out.println("玩儿");
    }
}

public class UserTen extends UserAdapter {
    @Override
    public void eat() {
        System.out.println("吃饭");
    }

    @Override
    public void drink() {
        System.out.println("喝水");
    }
}

调用方式:

IUser userNine = new UserNine();
userNine.eat();
userNine.drink();
userNine.play();

IUser userTen = new UserTen();
userTen.eat();
userTen.drink();

这样一来,接口中随意加方法,然后在在适配器类中添加对应方法的默认实现,最后在需要实现新方法的实现类中加入对应的个性化实现就好了。

策略模式

策略模式允许根据不同的策略来执行不同的行为。在这种情况下,可以将新方法定义为策略接口,然后为每个需要实现新方法的实现类提供不同的策略。

把接口改成抽象类,这里面 eat() 和 drink() 方法不变,可以什么都不做,实现类里想怎么自定义都可以。

而 play() 这个方法是后来加入的,所以我们重点关注 play() 方法,策略模式里的策略就用在 play() 方法上。

public abstract class AbstractUser {

    IPlayStrategy playStrategy;
  
   public void setPlayStrategy(IPlayStrategy playStrategy){
        this.playStrategy = playStrategy;
    }
  
    public void play(){
        playStrategy.play();
    }

    public void eat() {
        // 默认实现
    }

    public void drink() {
        // 默认实现
    } 
}

IPlayStrategy是策略接口,策略模式是针对行为的模式,玩儿是一种行为,当然了,你可以把之后要添加的方法都当做行为来处理。

我们定一个「玩儿」这个行为的策略接口,之后不管你玩儿什么,怎么玩儿,都可以实现这个 IPlayStrategy接口。

public interface IPlayStrategy {

    void play();
}

然后现在做两个实现类,实现两种玩儿法。

第一个玩儿游戏的实现

public class PlayGameStrategy implements IPlayStrategy{

    @Override
    public void play() {
        System.out.println("玩游戏");
    }
}

第二个玩儿足球的实现

public class PlayFootballStrategy implements IPlayStrategy{
    @Override
    public void play() {
        System.out.println("玩儿足球");
    }
}

然后定义 AbstractUser的子类

public class UserOne extends AbstractUser{
    @Override
    public void eat() {
        //自定义实现
    }

    @Override
    public void drink() {
        //自定义实现
    }
}

调用方式:

public static void main(String[] args) {
  AbstractUser userOne = new UserOne();
  // 玩儿游戏
  userOne.setPlayStrategy(new PlayGameStrategy());
  userOne.play();
  // 玩儿足球
  userOne.setPlayStrategy(new PlayFootballStrategy());
  userOne.play();
}

整体的类关系图大概是这个样子:

图片

最后

通过适配器模式和策略模式,我们即可以保证具体的实现类实现共同的接口或继承共同的基类,同时,又能在新增功能(方法)的时候,尽可能的保证设计的清晰。不像之前那种破罐子破摔的方式,接口和实现类几乎脱离了关系,每个实现类,各玩儿各的。

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

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

相关文章

java(Collection类)

文章目录 Collection接口继承树Collection接口及方法判断删除其它 Iterator(迭代器)接口迭代器的执行原理 foreach循环Collection子接口1:ListList接口特点List接口方法List接口主要实现类:ArrayListList的实现类之二:LinkedListList的实现类…

【python】我用python写了一个可以批量查询文章质量分的小项目(纯python、flask+html、打包成exe文件)

web 效果预览: 文章目录 一、API 分析1.1 质量分查询1.2 文章url获取 二、代码实现2.1 Python2.11 分步实现2.12 一步完成2.13 完整代码 2.2 python html2.21 在本地运行2.22 打打包成exe文件2.23 部署到服务器 一、API 分析 1.1 质量分查询 先去质量查询地址&a…

处理nacos、tomcat、nginx日志增长过快问题

1.nacos日志清理 修改nacos-logback.xml 将日志级别改为error级&#xff0c;减少info级日志产生量 将<maxHistory>调整为2以下&#xff0c;将 <totalSizeCap>调整为2GB左右 比如&#xff1a; [rootiZ0jlapur4hqjezy8waee0Z logs]# ll -h total 2.1G -rw-r--r-…

mysql忘记密码重置密码步骤

1.使用管理员权限打开cmd窗口&#xff0c;winr后输入cmd&#xff0c;然后按CtrlShiftEnter. 2.停止mysql服务&#xff0c;如上图net stop mysql 3.找到mysql安装目录下的my.ini文件&#xff0c;使用管理员权限打开 4.在[mysqld]下面新增一行skip-grant-tables 5.启动mysql服务…

新的恶意软件 WikiLoader 针对意大利组织

研究人员发现了一种新的恶意软件&#xff0c;名为 WikiLoader 恶意软件。之所以这样命名&#xff0c;是因为它向维基百科发出请求&#xff0c;希望得到内容中包含 "The Free "字符串的响应。 WikiLoader 恶意软件的主要目标是意大利企业及组织。 WikiLoader 是一种…

微信到底可以添加多少好友?怎么避免加人频繁?

微信作为一款用户月活跃量超过10亿的社交聊天软件&#xff0c;已经成为人们生活中不可或缺的一部分。 微信好友上限1万个 01 不知道有没有小伙伴好奇&#xff0c;微信到底可以添加多少好友&#xff1f;正好这个话题也上热搜了&#xff0c;我们就来了解一下。 有网友表示&…

Android安卓实战项目(6)---健身运动 APP实现健身运动倒计时显示提醒(源码在文末)

Android安卓实战项目&#xff08;6&#xff09;—健身运动 APP实现健身运动倒计时&#xff08;源码在文末&#x1f415;&#x1f415;&#x1f415;&#xff09; 一.项目运行介绍 【bilibili演示】 https://www.bilibili.com/video/BV1414y167WH/?share_sourcecopy_web&…

接受平庸,特别是程序员

目录 方向一&#xff1a;简述自己的感受 方向二&#xff1a;聊聊你想怎么做 方向三&#xff1a;如何调整自己的心态 虽然清楚知识需要靠时间沉淀&#xff0c;但在看到自己做不出来的题别人会做&#xff0c;自己写不出的代码别人会写时还是会感到焦虑怎么办&#xff1f; 你是…

棕榈酰四肽-7——促进皮肤自然愈合和再生

简介 棕榈酰四肽-7&#xff08;Palmitoyl Tetrapeptide-7&#xff09;可以延缓和抑制过量细胞白介素的生成&#xff0c;从而抑制一些不必要不恰当的炎症反应和糖基化损伤。在体外实验中&#xff0c;科学家们发现在细胞白介素生成时&#xff0c;“棕榈酰四肽-7诱导呈现出一种显…

2023-08-02 LeetCode每日一题(翻转卡片游戏)

2023-08-02每日一题 一、题目编号 822. 翻转卡片游戏二、题目链接 点击跳转到题目位置 三、题目描述 在桌子上有 N 张卡片&#xff0c;每张卡片的正面和背面都写着一个正数&#xff08;正面与背面上的数有可能不一样&#xff09;。 我们可以先翻转任意张卡片&#xff0c;…

【Unity3D】Shader Graph简介

1 Shader Graph 简介 Shader Graph 是 Unity 官方在 2018 年推出的 Shader 制作插件&#xff0c;是图形化的 Shader 制作工具&#xff0c;类似于 Blender 中的 Shader Editor 和 UE 中的 Material Editor&#xff0c;它使用流程图的形式表达顶点变换和片元着色的流程。 Shader …

GC垃圾回收器【入门笔记】

GC&#xff1a;Garbage Collectors 垃圾回收器 C/C&#xff0c;手动回收内存&#xff1b;难调试、门槛高。忘记回收、多次回收等问题 Java、Golang等&#xff0c;有垃圾回收器&#xff1a;自动回收&#xff0c;技术门槛降低 一、如何定位垃圾&#xff1f; https://www.infoq.c…

<C++>二、 类和对象

1.面向对象和面向过程 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c; 通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间的交互完成。 2. C类 C…

直击运维痛点,大数据计算引擎 EasyMR 的监控告警设计优化之路

当企业的业务发展到一定的阶段时&#xff0c;在系统中引入监控告警系统来对系统/业务进行监控是必备的流程。没有监控或者没有一个好的监控&#xff0c;会导致开发人员无法快速判断系统是否健康&#xff1b;告警的实质则是“把人当服务用”&#xff0c;用告警通知人的方式去干预…

小研究 - 微服务系统服务依赖发现技术综述(二)

微服务架构得到了广泛的部署与应用, 提升了软件系统开发的效率, 降低了系统更新与维护的成本, 提高了系统的可扩展性. 但微服务变更频繁、异构融合等特点使得微服务故障频发、其故障传播快且影响大, 同时微服务间复杂的调用依赖关系或逻辑依赖关系又使得其故障难以被及时、准确…

SVN代码迁移到Git方法

1.在SVN上新增一个项目 一、点击新建项目 二、创建空白项目 三、填入项目信息 四、myProject项目模板创建成功 2.将代码提交到Git 一、新建一个文件夹myProject&#xff0c;将从SVN下载过来的代码复制一份拷贝到该文件夹下&#xff0c;注意&#xff1a;不要把.SVN文件拷…

兴达易控Profinet转Modbus RTU主站模式的配置流程

兴达易控Profinet转Modbus RTU主站网关&#xff0c;能够实现不同协议之间的设备数据传输。这种设备具有高度的可靠性和稳定性&#xff0c;能够满足工业领域对通信设备的严格要求。同时&#xff0c;兴达易控Profinet转Modbus RTU主站还具备简单易用的特点&#xff0c;使用现场能…

安防视频监控平台EasyCVR修改参数提示database or disk is full的原因排查

EasyDarwin开源流媒体视频EasyCVR安防监控平台可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等能力。视频监控综合管理平台EasyCVR具备视频汇聚融合能力&#xff0c;平台基于云边端一体化架构&#xff0c;具有强大…

查看内存类型和频率 - Win系统

查看内存类型和频率 - Win系统 问题方法1&#xff08;推荐&#xff09;&#xff1a;使用命令行方法2&#xff1a;使用CPU-Z方法3&#xff1a;使用AIDA64 问题 我们在为电脑扩充内存时需要提前了解电脑内存的类型和频率&#xff0c;防止内存不兼容&#xff0c;但在设备管理器和…

从零实现深度学习框架——Transformer从菜鸟到高手(一)

引言 &#x1f4a1;本文为&#x1f517;[从零实现深度学习框架]系列文章内部限免文章&#xff0c;更多限免文章见 &#x1f517;专栏目录。 本着“凡我不能创造的&#xff0c;我就不能理解”的思想&#xff0c;系列文章会基于纯Python和NumPy从零创建自己的类PyTorch深度学习框…