1 设计模式原则之开闭原则

news2024/11/25 0:15:22

一、开闭原则

1.定义

开闭原则:对扩展开放,对修改关闭

2.具体用法

        在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。

        想要达到这样的效果,我们需要使用接口和抽象类。

        因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。

3.代码举例

public class Client {
    public static void main(String[] args) {
        //创建搜狗输入法
        SouGouInput souGouInput = new SouGouInput();
        //创建皮肤对象
        DefaultSkin defaultSkin = new DefaultSkin();
        //将皮肤设置到输入法
        souGouInput.setSkin(defaultSkin);
        //显示皮肤
        souGouInput.display();
    }
}


public abstract class AbstractSkin {
    //显示的方法
    public abstract void display();
}


public class DefaultSkin extends AbstractSkin{
    public void display(){
        System.out.println("默认皮肤 ");
    }

}

public class CSDNSkin extends AbstractSkin{

    @Override
    public void display() {
        System.out.println("欢迎使用Theodore的皮肤!");
    }
}


public class SouGouInput {
    private AbstractSkin skin;

    public void setSkin(AbstractSkin skin) {
        this.skin = skin;
    }

    public void display(){
        skin.display();
    }
}


4.案例讲解

(1)抽象类 AbstractSkin:为扩展皮肤做好准备

public abstract class AbstractSkin { 
    public abstract void display(); 
}
  • 这是一个 抽象类,定义了一个抽象方法 display(),用来显示皮肤。
  • 为什么要这样设计?
    • 这样做的目的是:为未来新增不同的皮肤提供扩展能力。只要继承这个抽象类并实现 display 方法,就可以定义新的皮肤。
  • 开闭原则体现
    • 对扩展开放:未来我们可以新增任何皮肤类,而不需要修改 AbstractSkin 类本身。
    • 对修改关闭:无需修改 AbstractSkin 类的代码,只需要新增子类实现新的功能。

(2)具体皮肤类 DefaultSkinCSDNSkin:通过扩展实现新功能

public class DefaultSkin extends AbstractSkin { 
    public void display() { 
        System.out.println("默认皮肤"); 
    } 
} 
public class CSDNSkin extends AbstractSkin { 
    @Override public void display() { 
        System.out.println("欢迎使用Theodore的皮肤!"); 
    } 
}
  • 这里我们定义了两个具体的皮肤类,分别是默认皮肤和 CSDN 皮肤。
  • 开闭原则体现
    • 对扩展开放:如果以后你想新增一个皮肤,比如说 “暗黑皮肤”,只需要新建一个 DarkModeSkin 类,继承 AbstractSkin,并实现 display 方法。
    • 对修改关闭:你无需修改 DefaultSkinCSDNSkin 的代码,就可以新增新的皮肤类。

(3)输入法类 SouGouInput:通过抽象类实现扩展性

public class SouGouInput {
    private AbstractSkin skin; // 依赖于抽象类

    public void setSkin(AbstractSkin skin) {
        this.skin = skin;
    }

    public void display() {
        skin.display();
    }
}
  • SouGouInput 类表示搜狗输入法,它并不知道有哪些具体皮肤,只知道这些皮肤都是 AbstractSkin 的子类。
  • 开闭原则体现
    • 对扩展开放:你可以传入任何 AbstractSkin 的子类,比如 DefaultSkinCSDNSkin 或未来的 DarkModeSkin
    • 对修改关闭SouGouInput 类的代码并不需要因为新增了新皮肤而进行任何修改。

(4)客户端类 Client:使用不同皮肤而不改动输入法

public class Client {
    public static void main(String[] args) {
        SouGouInput souGouInput = new SouGouInput();
        
        // 使用默认皮肤
        souGouInput.setSkin(new DefaultSkin());
        souGouInput.display();
        
        // 切换到 CSDN 皮肤
        souGouInput.setSkin(new CSDNSkin());
        souGouInput.display();
    }
}

输出结果

默认皮肤
欢迎使用Theodore的皮肤!
  • 开闭原则体现
    • 在客户端中,SouGouInput 可以使用任意的皮肤,而无需修改 SouGouInput 类的核心逻辑。
    • 如果想新增一个皮肤,比如暗黑皮肤,只需要这样写:
      souGouInput.setSkin(new DarkModeSkin());
      souGouInput.display();
      
      新增的皮肤功能可以被无缝集成,而无需对已有代码做出修改。

5.总结

通过这个例子,我们可以看到,开闭原则 是如何帮助我们设计出 灵活且易于扩展 的代码结构:

  1. 抽象类 AbstractSkin 提供扩展点:所有新皮肤都通过继承这个类来扩展功能。
  2. SouGouInput 类依赖抽象类,而不是具体实现:这让输入法系统无需修改现有代码即可使用新的皮肤。
  3. 新增功能不改动现有代码:新增皮肤只需创建新的子类,不需要修改 SouGouInput 和已有的皮肤类。

这样,我们既能满足用户不断变化的需求(比如新增不同风格的皮肤),又能保证现有代码的稳定性,减少修改代码引入错误的风险。

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

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

相关文章

三十一、构建完善微服务——API 网关

一、API 网关基础 系统拆分为微服务后,内部的微服务之间是互联互通的,相互之间的访问都是点对点的。如果外部系统想调用系统的某个功能,也采取点对点的方式,则外部系统会非常“头大”。因为在外部系统看来,它不需要也没…

深入理解 Redis跳跃表 Skip List 原理|图解查询、插入

1. 简介 跳跃表 ( skip list ) 是一种有序数据结构,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。 在 Redis 中,跳跃表是有序集合键的底层实现之一,那么这篇文章我们就来讲讲跳跃表的实现原理。 2. …

MediaSession学习总结

1.框架预览 2.用法 2.1参考链接: MediaSession 简单使用 2.2 服务端要实现MediaBrowserService; 主要实现的功能: mPlaybackState new PlaybackStateCompat.Builder().setState(PlaybackStateCompat.STATE_NONE, currentPostion, 1.0f).…

学习大数据DAY61 宽表加工

目录 模型设计 加工宽表 任务调度: 大表 - 把很多数据整合起来 方便后续的明细查询和指标计算 模型设计 设计 建模 设计: excel 文档去编写 建模: 使用建模工具 PowerDesigner Navicat 在线画图工具... 把表结构给绘 制出来 共享\项目课工具\pd 加工宽表 数…

零基础入门Flink,掌握基本使用方法

Flink基本概念 首先来讲,Flink是一个面向数据流处理和批处理的分布式开源计算框架。 那么,流处理和批处理分别处理什么样的数据呢,这就涉及两个概念-无界流和有界流 无界流VS有界流 任何类型的数据都可以形成流数据,比如用户…

Linux设置以及软件的安装(hadoop集群安装02)

一、Linux的常见设置 1、设置静态IP vi /etc/sysconfig/network-scripts/ifcfg-ens33 如何查看自己的虚拟机的网关: 完整的配置(不要拷贝我的): TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no&…

数据中台方法论:数据汇聚

文章目录 一、数据汇聚概述二、 汇聚数据类型2.1 结构化数据2.2 半结构化数据2.3 非结构化数据 三、汇聚数据模式四、汇聚数据方法四、数据汇聚工具五、数据汇聚使用经验 数据小伙伴们,之前咱们长篇大论的聊聊过【数据中台建设方法论从0到1】,从数据中台…

【Maven】nexus 配置私有仓库配置【转】

介绍:【Maven】Nexus几个仓库的介绍-CSDN博客 一、仓库类型 proxy 远程仓库的代理,比如说nexus配置了一个central repository的proxy,当用户向这个proxy请求一个artifact的时候,会现在本地查找,如果找不到,则会从远程…

3C产品说明书电子化转变:用户体验、环保与商业机遇的共赢

在科技日新月异的当代社会,3C产品(涵盖计算机类、通信类和消费类电子产品)已成为我们日常生活中不可或缺的重要元素。与此同时,这些产品的配套说明书也经历了一场从纸质到电子化的深刻变革。这一转变不仅体现了技术的飞速进步&…

【YOLOv8】安卓端部署-2-项目实战

文章目录 1 准备Android项目文件1.1 解压文件1.2 放置ncnn模型文件1.3 放置ncnn和opencv的android文件1.4 修改CMakeLists.txt文件 2 手机连接电脑并编译软件2.1 编译软件2.2 更新配置及布局2.3 编译2.4 连接手机 3 自己数据集训练模型的部署4 参考 1 准备Android项目文件 1.1…

虚拟网卡驱动和DM9000C移植

网卡驱动程序框架 网卡驱动程序“收发功能”: 只要把上层的数据发给网卡,从网卡来的数据构造成包给上层即可。网卡只需要 “socket”编程,不需要打开某设备。 驱动程序都是以面向对象的思想写的,都有相关的结构体。 编程步骤 …

Vue3 + Vite 项目引入 Typescript

文章目录 一、TypeScript简介二、TypeScript 开发环境搭建三、编译方式1. 自动编译单个文件2. 自动编译整个项目 四、配置文件1. compilerOptions基本选项严格模式相关选项(启用 strict 后自动包含这些)模块与导入相关选项 2. include 和 excludeinclude…

Cyberchef使用功能之-多种压缩/解压缩操作对比

cyberchef的compression操作大类中有大量的压缩和解压缩操作,每种操作的功能和区别是什么,本章将进行讲解,作为我的专栏《Cyberchef 从入门到精通教程》中的一篇,详见这里。 关于文件格式和压缩算法的理论部分在之前的文章《压缩…

Istio分布式链路监控搭建:Jaeger与Zipkin

分布式追踪定义 分布式追踪是一种用来跟踪分布式系统中请求的方法,它可以帮助用户更好地理解、控制和优化分布式系统。分布式追踪中用到了两个概念:TraceID 和 SpanID。 TraceID 是一个全局唯一的 ID,用来标识一个请求的追踪信息。一个请求…

Linux修改/etc/hosts不起作用(ping: xxx: Name or service not known)的解决方法——开启NSCD

​ 问题描述 起因是我在实验室云资源池的一台虚拟机(CentOS 8.5)上的/etc/hosts文件中为Fabric网络节点的域名指定了IP: IP可以ping通,但是ping域名时提示ping: xxx: Name or service not known。 问题本身应该是Linux通用的&a…

Python中Tushare(金融数据库)入门详解

文章目录 Python中Tushare(金融数据库)入门详解一、引言二、安装与注册1、安装Tushare2、注册与获取Token 三、Tushare基本使用1、设置Token2、获取数据2.1、获取股票基础信息2.2、获取交易日历2.3、获取A股日线行情2.4、获取沪股通和深股通成份股2.5、获…

【网络】网络抓包与协议分析

网络抓包与协议分析 一. 以太网帧格式分析 这是以太网数据帧的基本格式,包含目的地址(6 Byte)、源地址(6 Byte)、类型(2 Byte)、数据(46~1500 Byte)、FCS(4 Byte)。 Mac 地址类型 分为单播地址、组播地址、广播地址。 单播地址:是指第一个字节的最低位…

RabbitMQ的工作队列在Spring Boot中实现(详解常⽤的⼯作模式)

上文着重介绍RabbitMQ 七种工作模式介绍RabbitMQ 七种工作模式介绍_rabbitmq 工作模式-CSDN博客 本篇讲解如何在Spring环境下进⾏RabbitMQ的开发.(只演⽰部分常⽤的⼯作模式) 目录 引⼊依赖 一.工作队列模式 二.Publish/Subscribe(发布订阅模式) …

python学习_3.正则表达式

来源:B站/麦叔编程 1. 正则表达式的7个境界 假设有一段文字: text 身高:178,体重:168,学号:123456,密码:9527要确定文本中是否包含数字123456,我们可以用in运算符,也可以使用inde…

Python学习------第十天

数据容器-----元组 定义格式,特点,相关操作 元组一旦定义,就无法修改 元组内只有一个数据,后面必须加逗号 """ #元组 (1,"hello",True) #定义元组 t1 (1,"hello") t2 () t3 tuple() prin…