【设计模式】六大原则-上

news2024/11/16 3:32:00

首先什么是设计模式?

相信刚上大学的你和我一样,在学习这门课的时候根本不了解这些设计原则和模式有什么用处,反而不如隔壁的C++更有意思,至少还能弹出一个小黑框,给我个hello world。

如何你和我一样也是这么想,那接下来咱们以贴合生活实际的方式来看看设计模式到底有什么神奇的地方

【设计模式】六大原则

  • 设计模式存在的意义是什么
  • 六大原则
    • 开闭原则
    • 里氏代换原则
    • 依赖倒转原则
  • 应用样例
    • 业务简介
    • 怎么设计呢
    • 实现
  • 总结

设计模式存在的意义是什么

在了解设计模式之前我们还是先考虑一下设计模式的意义是什么

不然光知道了结论,不知道是干啥的,这和没学好像也没啥区别。

在这里插入图片描述

咱们还是从以做系统为例来聊吧。

我们实现了一个很简单的仓库系统。早期的时候你只设计了存储胡萝卜的过程,大致流程就是拿起胡萝卜=》丢到仓库=》关闭仓库门,功能很快就实现了。

但是之后加需求了,仓库里可以存储液体了,可以认为多了一口大缸,比如现在我要存啤酒,那么与胡萝卜不同的是我不能直接把啤酒丢进去,我需要把啤酒倒进缸中,那之前的代码就不适用了,那咋办呀?

此时,一个大聪明提议,加个判断嘛,这不就ok了,然后风风火火的写完了,功能依旧正常,代码也还可以看得懂。

但是时间一长就有问题了,后续又需要往仓库中放更多种类的东西,并且存放过程并不一致,大家还是if else的堆叠。这个时候你看着现在的代码陷入了沉思,这好几千行,看都得看一会。幸好的是,目前还能跑得动,功能也正常。

但谁能想到,仓库搬家了,这就意味着我们原来把东西放到仓库步骤里存放过程都要改,好家伙,这可是个大工程,你看这好几千行的代码,只能开始了加班,心里想着要是最开始的项目架构设计的合理一点就好了,这样就不至于加班这么晚了,这个时候你才想起来了大学时期学习的那一门叫做设计模式的课程。
在这里插入图片描述

没错,设计模式简单来说就是前人总结的软件开发经验,让我们在后期需求增加,需求变动时不至于那么被动,并且可以极大的提高代码的可读性和重用性。

那我们怎么才能优化上面的仓库系统呢?

别着急,了解完设计模式你就清楚了。

六大原则

开闭原则

对扩展开放,对修改关闭。

相信大家已经读完一遍了,咋样,有没有豁然开朗的感觉

反正我没有,这都是啥!!!

在这里插入图片描述
言归正传,咱还得看看到底咋回事。

这里的扩展可以理解为增加新的业务逻辑代码,修改则可以认为修改原有的代码。

那为啥得这么做呢?

试想一下,一个极其复杂逻辑的业务代码,经过你无数次的debug和修改之后终于可以运行了,并且功能也没问题。这个时候一个并不清楚你的实现逻辑的一个楞头小子要扩展你的业务,并且扩展的方式还是修改你的源代码,不出意外,又跑不起来了。

在这里插入图片描述

那如果我们在最初设计的时候就严格遵守了开闭原则,也就是说让后面的人添加新业务的时候只添加新代码而不修改源代码,那会不会好一点?

那要咋做呢?

看看下面的代码可以吗?

public interface Example {
    public void operate();
    public void setNextOne(Example example);
}


public class OneExample implements Example {

    Example nextOne;

    @Override
    public void operate() {

        System.out.println("一系列处理");
        if(nextOne!=null)
        nextOne.operate();
    }

    @Override
    public void setNextOne(Example example) {
        nextOne = example;
    }
}


public class ExampleTest {
    public static void main(String[] args) {
        Example oneExample = new OneExample();
        oneExample.operate();
    }
}


看到上面的代码,你可能会疑惑,这就能在满足开闭原则的条件下增加功能嘛?

是的,可以的,为啥呢?

这里我们首先要明确一个点哈,这里我们要满足的开闭原则并不是严格意义上的开闭原则,只是对核心业务代码保证开闭原则。

听到这有点绕,这是啥意思呢?

也就是说我们并不会修改原来的核心业务代码,也就是OneExample 的operate方法,因为这里面的代码逻辑我们并不清楚,随意修改容易出现问题。但是我们会修改ExampleTest中的方法,把我们添加的新功能放进去即可。

那怎么放呢?添加代码如下

public class TwoExample implements Example {

    Example nextOne;
    @Override
    public void operate() {
        System.out.println("新添加的业务逻辑");
         if(nextOne!=null)
       nextOne.operate();
    }
  @Override
    public void setNextOne(Example example) {
        nextOne = example;
    }
}


public class ExampleTest {
    public static void main(String[] args) {
        Example oneExample = new OneExample();
        Example twoExample = new TwoExample();
        oneExample.setNextOne(twoExample);
        oneExample.operate();
    }
}

看到这里你会发现,利用下面这个代码就可以很优雅的执行新添加的流程。

if(nextOne!=null)
       nextOne.operate();

这样确实方便后续功能的添加,并且不会修改咱们原来的写的代码,这样就避免了大聪明把我们好不容易调好的代码又改成bug的问题。

这时候有小伙伴就会说了,那我怎么能想到这么做呢?

那就要好好学设计模式的那些设计模式了,然后灵活应用了,上面的这种模式就是责任链模式,后面我们会仔细的讲,大家只要了解这种思想就够了。

到现在为止,再回顾一下,你就会发现设计模式的妙处,确实可以帮我们有效的提升开发和维护效率,不知道是不是提起你对设计模式的兴趣了呢。

在这里插入图片描述

里氏代换原则

所有引用基类 (父类)的地方必须能透明地使用其子类的对象。

ok,不出意外,估计大家和我一样,还是看的一头雾水。
在这里插入图片描述

我们用通俗的话解释一下。其实就是要求子类必须要实现父类的所有方法

这时候你不禁想问,这有啥好处呢?

我们可以把它作为开闭原则的扩展。具体有什么应用呢,我们来看看哈。

这里我们有一个汽车类Car,然后有三个实现类,比亚迪,蔚来,小鹏。Car有start,move,drift方法。现在我们有一辆比亚迪,我们要开出去,我们先看看不满足里氏代换的形式。

比亚迪 byd=new 比亚迪();
byd.start();
byd.move();
byd.drift();

由于父类无法完全调用子类的方法,我们只能使用子类来写代码,看着也好像还可以哈。

但是问题来了,我们换车了,开上蔚来了,那原来byd的代码不能用了呀,需要完全的写一遍,如下

蔚来 wl=new 蔚来();
wl.start();
wl.move();
wl.drift();

但如果遵循里氏代换之后呢?

Car car=new 比亚迪();
car.start();
car.move();
car.drift();

这个时候Car与比亚迪,蔚来,小鹏子类的方法一致,这个时候就可以直接使用父类接收子类对象,然后执行相应的操作。那我们怎么换成蔚来呢?

Car car=new 蔚来();
car.start();
car.move();
car.drift();

是不是这样就可以了,很轻松的进行修改。

结合上述两个例子,相信你也会发现所有开闭原则只是给了我们一个启发,但并不是说完全对修改关闭,而是核心业务代码对修改关闭即可。

看完这个之后,不知道你对设计模式是不是有一点新的体会了呢

依赖倒转原则

抽象不应该依赖于细节,细节应当依赖于抽象。

看得出来,这概念就挺抽象。

在这里插入图片描述

这又是啥意思呢?

以做菜为例子哈,我们想一下,我们要做一份西红柿炒鸡蛋,怎么写代码呢

大致过程是不是这样

切西红柿,打鸡蛋=》炒西红柿和鸡蛋

逻辑非常合理,并且代码写的也很简单。

但现在出现一个问题,我们换口味了,想吃胡萝卜炒鸡蛋,怎么做呢?

是不是原来的流程就不可以了,我们需要写一个新的流程,需要推翻原来的流程,变成下面这样

切胡萝卜,打鸡蛋=》炒胡萝卜和鸡蛋

随着需求的更改需要大幅度修改代码,这就说明我们的结构设计并不合理,并不稳定

那我们怎么才能再更改需求的时候并不会大幅度修改我们原来的架构呢

这时候就可以聊聊依赖倒转原则了。

首先,我们要明白一个概念,越抽象,越稳定

啥意思嘞

大家可能对抽象这个概念理解的就很抽象的,我们来通俗的聊聊。

其实,所谓的抽象的过程可以理解为总结事物或则流程的共同特征的过程。

例如哈,我们怎么抽象比亚迪,蔚来,小鹏,他们有一个共同点,都是汽车,还有什么共同点呢?都可以移动

这样我们就生成了他们的抽象,也就是一个包含移动方法的汽车类

这是总结事物,那怎么总结流程呢

像我们刚才聊的做菜,切胡萝卜,打鸡蛋和切西红柿本质上是不是都可以抽象为备菜炒胡萝卜,西红柿和鸡蛋是不是可以抽象为炒菜。那我们就可以改一下做菜的逻辑了。

备菜=》炒菜

很明显看出来,我们现在的流程实现就是依赖于抽象,而不是依赖实现了。

这样无论我们是要西红柿炒蛋还是胡萝卜炒蛋,都不需要修改原来的大体流程,只需要给备菜对象炒菜对象赋值对应的对象即可,我们的项目结构就是很稳定的。这样就可以很轻松的应对需求的变化,并且对源代码的修改是极小的。

应用样例

看了这么多原则,我们举的例子都是尽量方便大家理解,并没有结合实际业务,接下来咱们看看设计模式结合业务,代码会不会变得更优雅。

在这里插入图片描述

业务简介

你需要写一个请假流程,请假流程由两部分组成,第一部分是申请流程,可能需要多人批准,第二部分是排班。需要考虑后续申请排班业务的需求的变动

怎么设计呢

我们首先可以想到的是依赖倒转,就是依赖抽象实现任务,都不需要我们抽象了,题目都给好了,就是俩抽象,申请和排班

接下来就是考虑怎么可以满足开闭原则的前提下实现申请和排班业务?

我们是不是还是可以使用刚才用到的责任链模式去做,这样就可以保证不修改主要代码的情况下,对功能进行变更了。

这里简单讲一下责任链模式,不然大家容易看的云里雾里的。

我们画一张简单的图

在这里插入图片描述
他其实就是第一个链对象执行完毕,就会由下一个对象执行,直到执行到最后一个对象。

为什么说满足开闭原则呢?

因为我们在添加新功能的时候并不需要修改原来对象的业务逻辑,只需要把新添加的对象链接到链上即可,这样就增加了新的业务。

具体体现在代码是怎么弄的呢?

在这里插入图片描述
这样,就把twoexample链接到oneExample之后了,并且由于operate方法是这样的
在这里插入图片描述
这样,只要nextOne,也就是责任链的下一个链对象不为空,就会调用下一个对象的operate,这就实现了责任链。

里氏代换呢

别着急,看看实现就知道了怎么回事了。

实现

申请

public interface Apply {
    public void apply();

    public void setNextOne(Apply apply);
}


public class GroupApply implements Apply {
    Apply apply;

    @Override
    public void apply() {
        System.out.println("组长批准请假流程");
        // 这里就是可以像链路一样调用的关键
        if (apply != null)
            apply.apply();
    }

    @Override
    public void setNextOne(Apply apply) {
        this.apply = apply;
    }
}

public class BossApply implements Apply {
    Apply apply;

    @Override
    public void apply() {
        System.out.println("老板批准请假流程");
        // 这里就是可以像链路一样调用的关键
        if (apply != null)
            apply.apply();
    }

    @Override
    public void setNextOne(Apply apply) {
        this.apply = apply;
    }
}


调班

public interface Adjust {
    public void adjust();
    public void setNextOne(Adjust adjust);
}


public class FirstAdjust implements Adjust {
    Adjust adjust;

    @Override
    public void adjust() {
        System.out.println("进行排班");
        // 这里就是可以像链路一样调用的关键
        if(adjust!=null)
            adjust.adjust();
    }

    @Override
    public void setNextOne(Adjust adjust) {
           this.adjust=adjust;
    }
}


请假流程

public class MTest {
    public static void main(String[] args) {
        // 如果Apply或则Adjust的具体实现类变化了,直接修改引用即可,下面的业务逻辑代码不需要修改,这就是里氏代换和依赖倒置结合的好处。
        Apply groupApply = new GroupApply();

        Apply bossApply = new BossApply();
        // 把bossApply链接到groupApply之后,形成一条责任链
        // 后期有新的添加,像这种方式一样,链接到groupApply后即可,不需要修改原有的代码
        groupApply.setNextOne(bossApply);

        Adjust adjust = new FirstAdjust();


        groupApply.apply();
        adjust.adjust();
    }
}

可以看到哈,所有对象都是用的抽象接口,而不是实现,也就是我们之前提到的里氏代换

总结

初次了解设计模式,很难理解为什么需要这些准则和规范,但真正到了开发项目的时候就会突然了解前人的智慧。这种智慧不仅仅可以应用到项目设计中,同样也可应用到我们的做人做事上。

后续的三大原则很快更新,先写到这了。

在这里插入图片描述

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

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

相关文章

2-56 基于matlab的图像融合增强技术

基于matlab的图像融合增强技术。通过原始图像——傅里叶变换——频率域滤波处理——傅里叶变换——增强后的图像。傅立叶变换以及傅立叶反变换.过程就是将空间的信息分解为在频率上的表示,通过傅立叶正反变换的处理,才使得频率域上的处理可以用于图像的增强。程序已调通&#x…

联想QuickFix工具中心,一款综合性电脑维护和管理工具

联想QuickFix工具中心是联想公司推出的一款综合性电脑维护和管理工具,它集成了众多实用的电脑维护工具,如系统优化、硬盘清理、网络优化、硬件诊断等,旨在为用户提供一个便捷的平台来解决电脑日常使用中遇到的各种问题。该工具中心适用于Wind…

AttributeError: ‘ChatGLMTokenizer‘ object has no attribute ‘sp_tokenizer‘. 已解决

📑打牌 : da pai ge的个人主页 🌤️个人专栏 : da pai ge的博客专栏 ☁️宝剑锋从磨砺出,梅花香自苦寒来 ☁️运维工程师的职责:监…

【Linux---07】Shell脚本

文章目录 1. 前置说明1.1 创建shell脚本1.2 执行shell脚本1.3 调试shell脚本1.4 字符冲突 2. 变量2.1 创建&使用变量2.2 位置变量2.3 引号规则2.4 数值变量运算 3. 数组3.1 创建数组3.2 使用数组 4. 运算符4.1 比较运算符4.1.1 数字比较4.1.2 字符串比较 4.2 逻辑运算符4.3…

国内首个可调用API的视频模型,CogVideoX有多能打?

近期,智谱AI在其Maas开放平台(bigmodel.cn)发布了视频生成大模型CogVideoX,它提供了国内首个通过API来使用的文生视频和图生视频服务! 话不多说,我们直接来看一下通过CogVideoX生成的一部短片。 技术原理 CogVideoX融合了文本、…

CSP-J复赛-模拟题4

1.区间覆盖问题: 题目描述 给定一个长度为n的序列1,2,...,a1​,a2​,...,an​。你可以对该序列执行区间覆盖操作,即将区间[l,r]中的数字,1,...,al​,al1​,...,ar​全部修改成同一个数字。 现在有T次操作,每次操作由l,r,p,k四个值组成&am…

未授权访问漏洞系列详解⑦!

VNC未授权访问漏洞 VNC 是虚拟网络控制台 Virtual Network Console 的英文缩写。它是一款优秀的远程控制工具软件由美国电话电报公司AT&T的欧洲研究实验室开发。VNC是基于 UNXI和 Linux 的免费开源软件由 VNC Server 和 VNC Viewer 两部分组成。VNC 默认端口号为 5900、590…

opencascade AIS_TypeFilter AIS_XRTrackedDevice源码学习

opencascade AIS_TypeFilter 前言 通过它们的类型选择交互对象。该过滤器会对本地上下文中的每个交互对象提出问题, 以确定它是否具有非空的所有者,并且如果是,则检查它是否是所需类型。 如果对象在每种情况下都返回 true,则保留…

运动控制卡——固高GTS

文章目录 前言什么是运动控制卡指示灯状态检测主卡指示灯状态说明端子板指示灯状态说明 软件调试(P39)何将控制器配置成脉冲模式设置与定位 编程C#编程 一些概念 前言 在一些控制多轴电机运动的场景下,除了需要驱动器驱动该轴的电机外,还需要用到控制卡…

kickstart自动部署

目录 一 准备工作二 安装软件及其相关配置配置步骤,图形引导部署web服务配置dhcp部署pxe 三 使用新机验证 一 准备工作 主机采用rhel7.9版本 本文使用图形化界面就行操作设置 取消VMware dhcp设置 yum group install "Server with GUI" init 5 #启动图…

vue3中使用logicFlow

浅结logicFlow使用: 应用场景:vue3中使用logicFlow绘制流程图 技术碎片应用: vue3:ref,reactive, onMounted, watchEffect,nextTick,inject logicFlow:节点,边,锚点,事件 官网&#…

大模型微调fine-tuning

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl大模型微调概述 大模型fine-tuning(微调)是一种重要的机器学习技术,特别是在处理自然语言处理(NLP)任务时广泛应用。它指在已经预训练好的大型深度学习模型基础上,使用新的、特定任务相关的…

【文献阅读】GraphAny: A Foundation Model for Node Classification on Any Graph

Abstract 可以执行任何新任务而无需特定训练的基础模型已经在视觉和语言应用中引发了机器学习的革命。然而,涉及图结构数据的应用仍然是基础模型面临的一个难题,因为每个图都有独特的特征和标签空间。传统的图机器学习模型,如图神经网络&…

在Fragment中显示高德地图

一、首先在高德官网上申请key 第一步:按照规定填写Key名称第二步:选择服务平台,运用在android上就勾选anroid就好了第三步:输入发布版安全码SHA1 首先打开命令行按住windows+r两个按键在命令行中输入cd .android,定位到.android文件下调试版本使用 debug.keystore,命令为…

交通预测数据文件梳理:METR-LA

文章目录 前言一、adj_METR-LA.pkl文件读取子文件1读取子文件2读取子文件3 二、METR-LA.h5文件 前言 最近做的实验比较多,对于交通预测数据的各种文件和文件中的数据格式理解愈加混乱,因此打算重新做一遍梳理来加深实验数据集的理解,本文章作…

数位dp学习

参考借鉴: 数位DP学习整理(数位DP看完这篇你就会了)-CSDN博客 AcWing1081.度的数量(数位DP)题解_求给定区间$ [x,y]$ 中满足下列条件的整数个数:这个数恰好等于 k k k 个互不相等-CSDN博客 就是类似前缀和的思想,进行数字在位数…

最新资讯 | 开源大模型Llama会失去技术优势吗?

昨夜,Meta宣布推出迄今为止最强大的开源模型——Llama 3.1 405B,支持上下文长度为128K Tokens,在基于15万亿个Tokens、超1.6万个H100 GPU上进行训练,这也是Meta有史以来第一次以这种规模训练Llama模型。Meta同时还发布了全新升级的…

2024年,pdf文献热门翻译软件总结推荐

对于如今的时代,市面上存在各式各样的学术资料,对于没有语言天赋的我,看得眼花缭乱。看个学术资料都不知道要用哪个工具,试来试去和睦浪费时间。今天就我使用过的翻译软件中,整理了四款能帮助我们解决文献翻译难题的四…

未授权访问漏洞系列详解⑧!

Druid未授权访问漏洞 漏洞特征:http://www.xxxx.com/druid/index.html 当开发者配置不当时就可能造成未授权访问下面给出常见Druid未授权访问路径 ------------- /druid/websession.html /system/druid/websession.html /webpage/system/druid/websession.html(jeecg) ----…

GitHub惊天安全漏洞:删除的仓库竟能永远访问

引言 近日,GitHub 被曝出一个严重的安全漏洞,引发了广泛关注。开源安全软件公司 Truffle Security 的安全研究员 Joe Leon 发现,在 GitHub 上删除的代码仓库实际上仍然可以被访问。这一发现震惊了整个开源社区。本文将详细探讨这一安全漏洞的…