面向对象设计原则
在面向对象的设计过程中, 我们要对代码进行一个设计, 从而提高一个软件系统的可维护性和可复用性, 那么遵从面向对象的设计原则,可以在进行设计方案时减少错误设计的产生,从不同的角度提升一个软件结构的设计水平。
面向对象有以下七大原则:
1.单一职责原则:
单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小, 对于单一职责原则,可以理解为一个类只负责一个功能领域中的相应职责,即一个类不要负责太多“杂乱”的工作。
在软件系统中,如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时设计或遭受到意想不到的破坏。
以项目开发为例,如果项目组成员每个人的职责都很明确,可以专心开发自己负责的模块,则项目成果的质量往往很高。相反,如果职责不清晰,分工就会混乱。
优点: 低耦合,高内聚
2.开闭原则
开闭原则即对扩展开放,对修改封闭。在软件系统开发过程中,软件的需求往往会随着时间的推移而发生变化。因此,进行软件设计时需要考虑怎样的设计才能面对需求的改变却可以相对保持稳定,从而使得系统可以在第一个版本以后不断推出新的版本,这时便可以以开闭原则作为指导。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键, 在进行软件设计时,一般先评估出最有可能发生变化的类,然后构造抽象来隔离那些变化。当变化发生时,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。

示例:
(1)不使用开闭原则的功能的实现
public class CarDemo {public static void main(String[] args) {new CarFactory().createCar(1);new CarFactory().createCar(2);new CarFactory().createCar(3);new CarFactory().createCar(4);new CarFactory().createCar(5);}}/*汽车工程类,专门负责造汽车*/
class CarFactory{/*违反了开闭原则,后期如果添加新的汽车类,则需要修改代码*/public void createCar(int type){if(type==1){System.out.println("造宝马汽车"+new Car("宝马汽车"));}else if(type==2){System.out.println("造奥迪汽车"+new Car("奥迪汽车"));}else{System.out.println("造大众汽车"+new Car("大众汽车"));}}}class Car{String name;public Car(String name) {this.name = name;}
}
上述功能的实现需要修改原代码, 每一次新添加一个汽车类, 都需要新增加代码,实现起来非常麻烦
(2)使用开闭原则
class CarDemo{public static void main(String[] args) {new CarFactory().carfactory(new BMW());new CarFactory().carfactory(new Aodi());new CarFactory().carfactory(new DaZhong());}}
/*汽车工程类,专门负责造汽车*/
class CarFactory{void carfactory(Car car){car.createCar();}
}//抽象汽车类
abstract class Car{public abstract void createCar();
}
//宝马
class BMW extends Car{@Overridepublic void createCar() {System.out.println("造宝马汽车");}
}
//奥迪
class Aodi extends Car{@Overridepublic void createCar() {System.out.println("造奥迪汽车");}
}
//大众
class DaZhong extends Car{@Overridepublic void createCar() {System.out.println("造大众汽车");}
}
//奔驰
class BC extends Car{@Overridepublic void createCar() {System.out.println("造奔驰汽车");Calendar.getInstance();new GregorianCalendar();}
}
从以上代码可以看出来, 我每新添加一个功能只需要新添加一个类, 而不用修改原来的代码
这样会使得代码适用性和灵活性提高, 稳定性和延续性增强, 也拥有了较高的可复用性和可维护性
3.里氏替换原则
此原则是针对继承提出的, 虽然继承有很大的优势, 可以提高代码的复用性和可扩展性, 但是继承是侵入式的, 只要继承就必须拥有父类的属性和方法,体系结构复杂, 而且继承机制很大的增加了耦合性(父类被子类继承,父类功能修改会影响子类)
也就是说子类继承父类后,尽量不要重写父类的方法,可以新增扩展其他的功能, 保证子类功能的正确性. 不能让功能修改后,导致程序出错.
示例:
public class CalculatorDemo{public static void main(String[] args) {System.out.println(new SuperCalculator().sum(5,5,5));}}
//计算器 基类
class Calculator {//加法public int add(int a,int b){return a+b;}//减法public int sub(int a,int b){return a-b;}
}
/*超级计算器子类
*/
class SuperCalculator extends Calculator{//重写了父类加法@Overridepublic int add(int a, int b) {return a+b+5;}//求和方法 子类新增的功能public int sum(int a,int b,int c){//调用add(),但是子类重写了父类方法,此处调用的子类方法发生了变化int result = this.add(a,b);return result+c;}
}
以上代码可以可看出,子类重写了父类的add方法后, 子类所调用的默认的add方法就是自己重写后的方法, 而子类重写后更改了add方法的功能, 本来不重写默认调用的是父类中的add方法算下来是15, 但是子类重写后又加了5, 所以结果是20.
里氏替换原则克服了子类继承父类重写方法后可复用性变差的问题, 也提高了代码的可维护性, 降低了需求变更时引入的风险.
4.依赖倒置原则
上层模块不应该依赖底层模块,它们都应该依赖于抽象, 抽象不应该依赖于细节,细节应该依赖于抽象, 也就是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。也就是针对抽象层编程,面向接口编程

示例:
/*依赖倒置引入案例*/
public class WorkerDemo{public static void main(String[] args) {new Worker().getMessage(new DingDing());new Worker().getMessage(new WeChat());}
}class Worker {public void getMessage(DingDing ding){System.out.println(ding.sendMessage());}public void getMessage(WeChat weChat){System.out.println(weChat.sendMessage());}}//钉钉消息
class DingDing{public String sendMessage(){return "钉钉消息";}
}//微信消息
class WeChat{public String sendMessage(){return "微信消息";}
}
以上程序实现了不同平台发消息的功能, 如果要新增加一个平台或者更改一个平台就要对具体的实现(class Worker)进行更改
/*依赖倒置案例演示*/
public class WorkerDemo{public static void main(String[] args) {new Worker().getMessage(new WeChat());}}class Worker {public void getMessage(Message message){System.out.println(message.sendMessage());}}interface Message{public String sendMessage();
}class WeChat implements Message{@Overridepublic String sendMessage() {return "微信消息";}
}
class DingDing implements Message{@Overridepublic String sendMessage() {return "钉钉消息";}
}
如果我们定义一个接口, 每一个平台实现这个接口, 如果要更改平台, 不需要再具体的实现上进行修改, 从而降低客户与实现模块之间的耦合.
5.迪米特原则
它要求一个对象应该对其他对象有最少的了解,所以迪米特法则又叫做最少知识原则.
只和你的直接朋友交谈,不跟“陌生人”说话
直接朋友:
1. 类中的成员属性.
2. 在类中的方法作为参数使用.
3. 在类中的方法作为返回值类型.
迪米特法则的核心是降低类之间的耦合, 从被依赖者的角度来说,尽量将逻辑封装在类的内部,对外除了提供的public 方法,不泄露任何信息, 从依赖者的角度来说,只依赖应该依赖的对象, 切忌不要为了用而用
示例:
public class Demeter {public static void main(String[] args) {new SchoolManger().printAllEmployee(new CollegeManger());}
}/*学校员工类*/
class SchoolEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}/*学院员工类*/
class CollegeEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}//学院员工管理管理类
class CollegeManger{//生成学院所有的员工public List<CollegeEmployee> getCollegeEmployee(){ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<>();for (int i = 0; i <10 ; i++) {CollegeEmployee collegeEmployee = new CollegeEmployee();collegeEmployee.setId("学院员工的id="+i); //添加学院员工collegeEmployeeArrayList.add(collegeEmployee);}return collegeEmployeeArrayList;}}
//学校员工管理类
class SchoolManger {//生成学校的员工public List<SchoolEmployee> getSchoolEmployee() {ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<>();for (int i = 0; i < 5; i++) {SchoolEmployee employee = new SchoolEmployee();employee.setId("学校的员工id=" + i);employeeArrayList.add(employee);}return employeeArrayList;}//输出学校员工和学院员工信息public void printAllEmployee(CollegeManger collegeManger) {//获取到学校员工List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();System.out.println("--------学校员工--------");for (SchoolEmployee employee1 : employeeArrayList) {System.out.println(employee1.getId());}System.out.println("--------学院员工--------");List<CollegeEmployee> collegeEmployees = collegeManger.getCollegeEmployee();//此处学校管理类中出现CollegeEmployee,此类与SchoolManger并非直接朋友,不合理for (CollegeEmployee collegeEmployee : collegeEmployees) {System.out.println(collegeEmployee.getId());}}
}
最后在学校管理类中出现了不是它的朋友的类, 所以不太合理
6.接口隔离原则
使用多个接口,而不使用单一的总接口,不强迫新功能实现不需要的方法。

7.组合/聚合复用原则
优先使用组合,使系统更灵话,其次才考虑继承,达到复用的目的。一般而言,如果两个类之是"Has-A"关系应使用组合或聚合,如果是"Is-A"关系可使用继承。
案例:现在假设有一个 A 类,里面有两个方法,有一个类 B,想要复用这两个方法,请问有几种方案?
示例:
(1)继承实现
/*组合/聚合复用原则案例1 使用依赖实现复用*/
public class A {public void method01() {}public void method02() {}
}class B extends A {private A a;public void method() {}}class Test {public static void main(String[] args) {new B().method01();new B().method02();}
}
(2)使用关联的方法
/*组合/聚合复用原则案例2 使用组合/聚合实现复用*/
public class A {public void method01(){}public void method02(){}
}class B{A a;public void setA(A a){this.a = a;}public void use(){a.method01();a.method02();}}class Test{public static void main(String[] args) {A a = new A();B b = new B();b.setA(a);b.use();}
}
(3)依赖复用的方法,耦合性降低
/*组合/聚合复用原则案例3 使用依赖实现复用*/
public class A {public void method01(){}public void method02(){}
}class B{public void use(A a){a.method01();a.method02();}}class Test{public static void main(String[] args) {A a = new A();B b = new B();b.use(a);}
}
总结:
开闭原则:要求对扩展开放,对修改关闭
里氏替换原则:不要破坏继承体系
依赖倒置原则:要求面向接口编程
单一职责原则:实现类职责要单一
接口隔离原则:在设计接口的时候要精简单一
迪米特法则:只与直接的朋友的通信
合成复用原则:尽量使用聚合和组合的方式,而不是使用继承
设计原则的核心思想
找出应用中可能需要变化之处,独立出来,不要和不需要变化的代码混在一起
针对接口编程,而不是针对实现编程
为了交互对象的松耦合设计而努力
遵循设计原则:就是为了让程序高内聚,低耦合
相关文章:

面向对象设计原则
在面向对象的设计过程中, 我们要对代码进行一个设计, 从而提高一个软件系统的可维护性和可复用性, 那么遵从面向对象的设计原则,可以在进行设计方案时减少错误设计的产生,从不同的角度提升一个软件结构的设计水平。 面向对象有以下七大原则:1.单一职责原…...
2022年“网络安全”赛项湖南省赛选拔赛 任务书
2022年“网络安全”赛项湖南省赛选拔赛 任务书2022年“网络安全”赛项湖南省赛选拔赛 任务书A模块基础设施设置/安全加固(200分)B模块安全事件响应/网络安全数据取证/应用安全(400分)C模块 CTF夺旗-攻击 (200分&#x…...

学习笔记:Java 并发编程⑥_并发工具_JUC
若文章内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系博主删除。 视频链接:https://www.bilibili.com/video/av81461839配套资料:https://pan.baidu.com/s/1lSDty6-hzCWTXFYuqThRPw&am…...

Linux文件隐藏属性(修改与显示):chattr和lsattr
文件除了基本的九个权限以外还有隐藏属性存在,这些隐藏属性对于系统有很大的帮助,尤其是系统安全(Security)上 chattr(配置文件隐藏属性) chattr 【-】【ASacdistu】文件或目录名称 选项与参数:…...

广东省基层就业补贴
基层就业补贴链接:https://www.gdzwfw.gov.cn/portal/v2/guide/11440309MB2D27065K4440511108001 一.申请条件: 1、劳动者到中小微企业、个体工商户、社会组织等就业,或到乡镇(街道)、村居社会管理和公共服务岗位就业…...

高压放大器在超声导波钢轨传播中的应用
实验名称:高压放大器在超声导波钢轨传播中的应用研究方向:无损检测测试目的:超声导波具有传播距离远、检测距离长的特点,在钢轨无损检测领域受到越来越多的关注。本文使用有限元仿真方法和现场实验方法,对钢轨各模态超…...
Java字符串常见拼接方式
目录 最常见的方式 StringBuilder.append()和StringBuffer.append() String类下的cocat()方法 String类下的join()方法 StringUtils.join 项目中使用 不建议在 for 循环中使用 “” 进行字符串拼接 通过字符串连接,可以将两个或多个字符串、字符、整数和浮点…...

商城业务:购物车
人生在世如身处荆棘之中,心不动,人不妄动,不动则不伤;如心动则人妄动,伤其身痛其骨,于是体会到世间诸般痛苦。 1、购物车需求 1)、需求描述: - 用户可以在登录状态下将商品添加到购…...

计算机网络学习笔记(一)
网络是由若干接点和连接这些结点的链路组成。 多个网络通过路由器互联起来构成覆盖范围更大的互联网。 普通用户通过ISP接入因特网。 基于ISP的三层结构因特网 相隔较远的两台主机间通信可能需要经过多个ISP。 有电路交换,报文交换,分组交换三种交换方…...

【单目标优化算法】烟花优化算法(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

微服务项目【秒杀商品展示及商品秒杀】
登录方式调整 第1步:从zmall-common的pom.xml中移除spring-session-data-redis依赖 注意: 1)本次不采用spring-session方式,改用redis直接存储用户登录信息,主要是为了方便之后的jmeter压测; 2)…...

DIDL3_模型选择、复杂度、过欠拟合的相关概念
模型选择、复杂度、过欠拟合的概念模型选择训练误差和泛化误差验证数据集和测试数据集K-则交叉验证(没有足够多数据时使用)过拟合和欠拟合模型容量模型容量的影响估计模型容量控制模型容量数据复杂度处理过拟合的方法(1)ÿ…...
Android 9.0 去除锁屏界面及SystemUI无sim卡拨打紧急电话控件显示功能实现
1.1概述 在9.0的系统rom定制化开发中,关于SystemUI的定制化功能也是比较多的,在SystemUI的锁屏页面和状态栏提示无sim卡拨打紧急电话控件显示等相关提示 的功能中,在有些systemui的定制中是不需要这些功能的,所以需要从systemui中去掉这些功能提示的,这就需要从systemui中…...

AntDB-M设计之内存结构
亚信科技专注通信行业多年,AntDB数据库从诞生开始,就面对通信级的大数据量应用场景挑战,在性能、稳定性、规模化等方面获得了超过10年的通信核心业务系统验证,性能峰值达到每秒百万的通信核心交易量。AntDB-M(AntDB内存…...

互联网舆情监测公司监测哪些内容,TOOM北京舆情监测公司
互联网舆情监测公司是一种提供舆情监测、分析和管理服务的公司,其业务主要涉及互联网舆情监测、数据分析、报告撰写、危机处理等方面。这些公司通过使用各种技术和工具,帮助客户监测他们在互联网上的声誉和品牌形象,并提供相应的建议和解决方…...

一篇文章带你熟练使用Ansible中的playbook
目录 一、Playbook的功能 二、YAML 1、简介 2、特点 3、语法简介 4、YAML 列表 5、YAML的字典 三、playbook执行命令 四、 Playbook的核心组件 五、vim 设定技巧 练习 一、Playbook的功能 playbook 是由一个或多个play组成的列表 Playboot 文件使用YAML来写的 二、…...

HashedWheelTimer
序言这种算法是一种轮询算法的优化升级,能够以只有一个Timer的情况下处理大量的定时任务.Begin结合HashedWheelTimer的思想根据自然时间1分钟为例,来做大批量的定时任务触发首先定一个长度为60的数组,数组中存放的是Set集合,集合里面是任务详情.当有定时任务刚来的时候判断是否…...

OPenCV库移植到ARM开发板子上面配置过程
步骤一 1,环境准备去下载opencv官方的源码。 我这里用的是opencv-4.5.5版本的 2,还需要交叉编译工具一般,你交叉编译的工具板子厂家会提供工具,最好还是用板子厂家提供的交叉编译工具,因为我之前编译试过其他的交叉…...
Jenkins实现CI/CD
Jenkins是一个开源的持续集成和持续交付(CI/CD)解决方案,它可以自动执行构建、测试和部署等任务,从而简化了开发工作流程。本文将详细介绍如何使用Jenkins实现CI/CD。 首先,您需要安装Jenkins并启动它。您可以通过以下…...
如何给img标签里的请求添加自定义header
是这样的需求,有一个web页面,里面图片的上传和预览来自于一个独立的文件服务器,对http的请求需要进行访问权限的设置,就是在请求的header里加一个Authorization的字段。上传好说我用的Axios直接添加一个header就行了,但…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...