七大软件架构设计原则-读书笔记

news2024/11/27 17:47:05

7大原则

开闭原则(Open-Closed Principle,OCP)

指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。强调的是用抽象构建框架,用实现扩展细节,可以提高软件系统的可复用性及可维护性。开闭原则是面向对象设计中最基础的设计原则。它指导我们如何建立稳定灵活的系统,例如版本更新,我们尽可能不修改源码,但是可以增加新功能

demo1

1、课程接口ICourse
2、他有一个Java架构课程的类JavaCourse
3、现在要给Java架构课程做活动,价格优惠。
如果修改JavaCourse中的getPrice()方法,则会存在一定风险,可能影响其他地方的调用结果。
如何在不修改原有代码的前提下,实现价格优惠这个功能呢?
4、我们再写一个处理优惠逻辑的JavaDiscountCourse类,而不是直接修改JavaCourse类

ublic interface ICourse {
   Double getPrice();
}

public class JavaCourse implements ICourse {
    public Double price;
    public JavaCourse(Double price) {
        this.price = price;
    }
    @Override
    public Double getPrice() {
        return price;
    }
}

public class JavaDiscountCourse extends JavaCourse {
    public JavaDiscountCourse(Double price) {
        super(price);
    }
    public Double getDiscountPrice(Double discountRate) {
        return price * discountRate;
    }
    public Double getOriginPrice() {
        return price;
    }
}

依赖倒置原则(Dependence Inversion Principle,DIP)

指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象抽象不应该依赖细节,细节应该依赖抽象。通过依赖倒置,可以降低类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并降低修改程序带来的风险

demo1

public class Tom {
    public void studyEnglish(){}
    public void studyChinese(){}
}

public class MainBusiness {
    public static void main(String[] args) {
        Tom tom = new Tom();
        tom.studyEnglish();
        tom.studyChinese();
    }
}

Tom再追加学习画画的话。
这个时候,需要业务扩展,代码要从底层到高层(调用层)一次修改代码。
在Tom类中增加studyDraw()的方法,在高层也要追加调用。
如此一来,在系统发布以后,实际上是非常不稳定的,在修改代码的同时会带来意想不到的风险。

public interface ICourse {
    void study();
}
public class ChineseCourse implements ICourse {
    @Override
    public void study() {
    }
}
public class EnglishCourse implements ICourse {
    @Override
    public void study() {
    }
}
public class Daming {
    void study(ICourse course){
        course.study();
    }
}
public class MainBusiness {
    public static void main(String[] args) {
        Daming daming = new Daming();
        daming.study(new ChineseCourse());
        daming.study(new EnglishCourse());
    }
}

如上涉及到了代码注入,目前已知有31、作依赖注入
        Daming daming = new Daming();
        daming.study(new ChineseCourse());
        
2、构造器注入
		Daming daming = new Daming(new ChineseCourse());
		
3Setter注入方式(如果lingLing的ICourse是全局单例,则只能选择Setter注入方式)
        public class LingLing {
            ICourse course;
            public void setCourse(ICourse course) {
                this.course = course;
            }
            public void study() {
                course.study();
            }
        }

抽象为基准比以细节为基准搭建起来的架构要稳定得多,因此大家在拿到需求后,要面向接口编程,按照先顶层再细节的顺序设计代码结构。

单一职责原则(Simple Responsibility Principle,SRP)

不要存在一个以上导致类变更的原因。假设有一个Class负责两个职责,一旦发生需求变更,修改其中一个职责的逻辑代码,有可能会导致另一个职责的功能发生故障。这样一来,这个Class就存在两个导致类变更的原因。
如何解决这个问题呢?
我们就要分别用两个Class来实现两个职责,进行解耦。后期需求变更维护互不影响。这样的设计,可以降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。总体来说就是一个Class、Interface、Method只负责一项职责。

在实际项目中,代码会存在依赖、组合、聚合关系,在项目开发过程中还受到项目的规模、周期、技术人员水平、对进度把控的影响,导致很多类都不能满足单一职责原则。但是,我们在编写代码的过程中,尽可能地让接口和方法保持单一职责,对项目后期的维护是有很大帮助的。

接口隔离原则(Interface Segregation Principle,ISP)

指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口

这个原则指导我们在设计接口时,应当注意以下几点。
(1)一个类对另一个类的依赖应该建立在最小接口上。
(2)建立单一接口,不要建立庞大臃肿的接口。
(3)尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)。

接口隔离原则符合“高聚合、低耦合”的设计思想,使得类具有很好的可读性、可扩展性和可维护性。在设计接口的时候,要多花时间思考,要考虑业务模型,包括还要对以后可能发生变更的地方做一些预判。所以,在实际开发中,我们对抽象、业务模型的理解是非常重要的。

demo1

public interface IAnimal {
    void fly();
    void swim();
    void run();
}

大多数时候鸟类的swim()方法可能只能空着,
陆地动物的fly()方法可能只能空着,代表接口就有些臃肿了
这时候,我们针对不同动物的行为来设计不同的接口
public interface IFlyAnimal {
    void fly();
}
public interface IRunAnimal {
    void run();
}
public interface ISwimAnimal {
    void swim();
}

迪米特法则(Law of Demeter,LoD)又叫作最少知道原则(Least Knowledge Principle,LKP)

指一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合。迪米特法则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入和输出参数中的类都可以被称为成员朋友类,而出现在方法体内部的类不属于朋友类

demo1

public class Task {}

public class Employee {
    void checkTask(List<Task> tasks){}
}

public class Leader {
    public void commandCheck(Employee employee){
        List<Task> taskList = new ArrayList<>();
        employee.checkTask(taskList);
    }
}
public class MainBusiness {
    public static void main(String[] args) {
        Leader leader = new Leader();
        Employee employee = getTaskList();
        leader.commandCheck(employee);
    }
}

代码实际意义:领导吩咐员工取检查任务

根据迪米特法则,TeamLeaderCourse并不是朋友。
Employee统计需要引用Course对象,Leader只想要结果,不需要跟Course产生直接交流。

PS:领导让你统计报表你让老板去替你收集数据也说不过去

public class Employee {
    void checkTask1(){
        List<Task> taskList = getTaskList();
        // 校验逻辑
    }
}
public class Leader {
    public void commandCheck1(Employee employee){
        employee.checkTask1();
    }
}
public class MainBusiness {
    public static void main(String[] args) {
        Leader leader = new Leader();
        Employee employee1 = new Employee();
        leader.commandCheck1(employee1);
    }
}

领导发话就可以了,不需要做任何员工的任务量

里氏替换原则(Liskov Substitution Principle,LSP)

指如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型

子类对象能够替换父类对象,而程序逻辑不变。说明,子类可以扩展父类的功能,但不能改变父类原有的功能。根据这个理解,我们对里氏替换原则的定义总结如下。

(1)子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
(2)子类中可以增加自己特有的方法。
(3)当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松。
(4)当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类的方法更严格或相等。

demo1

public class JavaCourse implements ICourse {
    public Double price;
    public JavaCourse(Double price) {
        this.price = price;
    }
    @Override
    public Double getPrice() {
        return price;
    }
}
public class JavaDiscountCourse extends JavaCourse {
    public JavaDiscountCourse(Double price) {
        super(price);
    }
    public Double getDiscountPrice(Double discountRate) {
        return price * discountRate;
    }
    public Double getOriginPrice() {
        return price;
    }
}

getOriginPrice() 就是典型的违反了里氏替换原则。我们不应该覆盖getPrice()方法

public class JavaDiscountCourse extends JavaCourse {
    public JavaDiscountCourse(Double price) {
        super(price);
    }
    public Double getDiscountPrice(Double discountRate) {
        return price * discountRate;
    }
    public Double getPrice() {
        return price;
    }
}

使用里氏替换原则有以下优点。
(1)约束继承泛滥,是开闭原则的一种体现。
(2)加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险。

合成复用原则(Composite/Aggregate Reuse Principle,CARP)

指尽量使用对象组合(has-a)或对象聚合(contanis-a)的方式实现代码复用,而不是用继承关系达到代码复用的目的。合成复用原则可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较小。

继承,又被称为白箱复用,相当于把所有实现细节暴露给子类。
组合/聚合又被称为黑箱复用,对类以外的对象是无法获取实现细节的。
我们要根据具体的业务场景来做代码设计,其实也都需要遵循面向对象编程(Object Oriented Programming,OOP)模型。

总结

在这里插入图片描述

-----------------------------------------------------------------------------摘自《设计模式就该这样学:基于经典框架源码和真实业务场景》(谭勇德)

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

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

相关文章

浅谈Redisson实现分布式锁对原理

1.Redisson简介 Redis 是最流行的 NoSQL 数据库解决方案之一&#xff0c;而 Java 是世界上最流行&#xff08;注意&#xff0c;我没有说“最好”&#xff09;的编程语言之一。虽然两者看起来很自然地在一起“工作”&#xff0c;但是要知道&#xff0c;Redis 其实并没有对 Java…

Win10开机输入密码后1分钟左右就蓝屏,一天出现10个不同蓝屏代码,如何解决

环境: DELL3480 Win10 专业版 问题描述: Win10 电脑开机输入密码后1分钟左右突然就蓝屏,一天出现10个不同蓝屏代码 1.BAD_SYSTEM_CONFIG_INFO bug 检查的值为 0x00000074。 此 bug 检查指示注册表中出现错误。 2.PAGE_FAULT_IN_NONPAGED_AREA bug 检查的值为 0x000…

修改redis的配置文件使得windows的图形界面客户端可以连接redis服务器

1. 安装 Redis 依赖 Redis 是基于 C语言编写的&#xff0c;因此首先需要安装 Redis 所需要的 gcc 依赖&#xff1a; yum install -y gcc tcl 2、上传安装文件 将下载好的 redis-6.2.7.tar.gz 安装包上传到虚拟机的任意目录&#xff08;一般推荐上传到 /usr/local/src目录&…

linux集群技术(三)--七层负载均衡-nginx

nginx特点nginx优势、缺点生产架构nginx 7层负载均衡语法示例nginx负载均衡算法测试案例生产案例 1.nginx特点 1. 功能强大,性能卓越,运行稳定。 2. 配置简单灵活。 3. 能够自动剔除工作不正常的后端服务器。 4. 上传文件使用异步模式。client---nginx---web1 web2 web3 lvs同…

uniapp: 基础开发官网文档

1、uniapp官网文档&#xff1a;https://uniapp.dcloud.net.cn/component/2、uView跨端UI组件库&#xff1a;http://v1.uviewui.com/components/intro.html3、lunch-request&#xff08;类似axios的请求库&#xff09;&#xff1a;https://www.quanzhan.co/luch-request/handboo…

图神经网络基础 Graph 图以及python实现

摘要&#xff1a; 本文将介绍图的基本知识、无向图、有向图、邻接矩阵 python实现&#xff1a;度、连通分量、强连通图、弱连通图、图直径、度中心性、特征向量中心性、中介中心性、连接中心性等基本概念。 python计算代码&#xff1a; 先安装依赖&#xff1a; pip install n…

Java-模块化

模块的基本使用 模块使用步骤 创建模块&#xff08;创建模块&#xff0c;创建包&#xff0c;创建类&#xff0c;定义方法&#xff09; -创建两个模块myOne,myTwo在模块的src目录下创建module-info.java的描述性文件&#xff0c;该文件专门定义模块名&#xff0c;访问权限&#…

一文读懂函数编程及其工作原理

微软MVP实验室研究员 马洪喜-微软 MVP 19年研发经验 云计算咨询顾问专家 容器云及基础架构云技术专家 DevOps 及微服务咨询专家 什么是函数编程 我先用通俗的大白话给大家解释一下函数(Functions, Function as a Service, FaaS)的几个要点&#xff0c;这样看后面示例时才不…

跑步带的耳机选择啥样的好、推荐几款跑步专用耳机

我是个比较喜欢运动的人&#xff0c;每天下班都会在小区湖边跑步健身&#xff0c;每次跑步要是少了耳机&#xff0c;那可没什么兴趣跑了&#xff0c;喜欢跑步的时候对着音乐的节奏跑&#xff0c;所以我的耳机基本上是用的比较紧实不易掉落的无线耳机。接下来我来为大家介绍下我…

ChatGPT 可收费的那种产品该如何实现?一点尝试

导读|时隔两个月&#xff0c;勇哥终于把chatGPT生成SQL的功能发布上线了&#xff0c;支持统计分析查询、创建表、数据生成等多种全面的SQL DDL生成能力&#xff0c;本文就和大家聊聊相关功能的使用和背后实现逻辑&#xff0c;并希望相关功能能帮助大家在工作中提升一定的工作效…

手把手搭建springboot项目05-springboot整合Redis及其业务场景

目录前言一、食用步骤1.1 安装步骤1.1.1 客户端安装1.2 添加依赖1.3 修改配置1.4 项目使用1.5 序列化二、应用场景2.1 缓存2.2.分布式锁2.2.1 redis实现2.2.2 使用Redisson 作为分布式锁2.3 全局ID、计数器、限流2.4 购物车2.5 消息队列 (List)2.6 点赞、签到、打卡 (Set)2.7 筛…

如何弄小程序?公司企业可以这样做小程序

公司企业现在对于小程序的需求已经是刚需了&#xff0c;即使已经有官网的情况下&#xff0c;也会考虑再弄一个小程序来做小程序官网。那么公司企业如何弄小程序呢&#xff1f;下面跟大家说说方法。 流程一、找小程序服务商 由于一些公司企业并不像现在的互联网公司企业那样有…

考试系统 (springboot+vue前后端分离)

系统图片 下载链接 地址&#xff1a; http://www.gxcode.top/code 介绍 一款多角色在线培训考试系统&#xff0c;系统集成了用户管理、角色管理、部门管理、题库管理、试题管理、试题导入导出、考试管理、在线考试、错题训练等功能&#xff0c;考试流程完善。 技术栈 Spr…

Java8中@Contended和伪共享

Java8引入了Contented这个新的注解来减少伪共享(False Sharing)的发生。 sun.misc.Contended注解是被设计用来解决伪共享问题的 文章目录1.缓存行2.伪共享(False Sharing)2.1 CPU的缓存机制3.填充(Padding)4.Contended方式4.总结1.缓存行 CPU读取内存数据时并非一次只读一个字…

ATTCK实战系列——红队实战(二)

网络配置 网卡&#xff1a; WEB&#xff1a; PC&#xff1a; DC&#xff1a; IPWEB10.10.10.80&#xff08;内&#xff09;/192.168.111.80&#xff08;外&#xff09;PC10.10.10.201&#xff08;内&#xff09;/192.168.111.201&#xff08;外&#xff09;DC10.10.10.10物理机…

评论字数统计案例、评论回车发布、 Tab 栏切换、验证码倒计时、显示与隐藏密码——DOM事件

目录 一、DOM事件 1. 评论字数统计案例 2. 评论回车发布 3. Tab 栏切换 4. 验证码倒计时 5. 显示与隐藏密码 一、DOM事件 1. 评论字数统计案例 该案例中的显示输入字数及最大字数模块.wrapper .total 刚开始是看不见的&#xff0c;使用的是不透明度&#xff08;opacit…

量化交易-单因子分析-alphalens

1. 数据准备 1.1 计算因子IC重要函数 def get_clean_factor_and_forward_returns(factor,prices,groupbyNone,binning_by_groupFalse,quantiles5,binsNone,periods(1, 5, 10),filter_zscore20,groupby_labelsNone,max_loss0.35,zero_awareFalse,cumulative_returnsTrue)facto…

Nginx优化与防盗链

Nginx优化与防盗链 &#x1f4d2;博客主页&#xff1a; 微笑的段嘉许博客主页 &#x1f4bb;微信公众号&#xff1a;微笑的段嘉许 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &#x1f4c…

图文并茂详解NAT协议(含实例分析)

什么是 NAT 协议 我们的计算机要想访问互联网上的信息&#xff0c;就需要一个地址&#xff0c;而且这个地址是大家&#xff08;其他主机&#xff09;所认可的&#xff0c;是公共的&#xff0c;这个地址也叫做公有 IP 地址。 与之相对的&#xff0c;除了公有 IP 地址外&#x…

Python自动化测试框架【Allure-pytest功能特性介绍】

Python自动化测试框架【Allure-pytest功能特性介绍】 目录&#xff1a;导读 前言 生成报告 测试代码 目录结构 Allure特性 Environment Categories Fixtures and Finalizers allure.attach 总结 写在最后 前言 Allure框架是一个灵活的轻量级多语言测试报告工具&am…