软件设计——面向对象的七大原则

前言

        软件设计模式和设计原则是成为一个软件架构师的基本功,较好的理解这些基础知识无疑是十分重要的。在这篇文章中荔枝将会比较详细梳理一下面向对象的七大原则,大家可以先看看这部分内容再去学习设计模式会比较好哈哈哈哈~~~


        在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,从而提高软件开发效率、节约软件开发成本和维护成本,开发必须要根据面向对象的七大原则来执行。首先我们需要了解一些术语:

  • 可维护性:在不破坏原有代码设计、不引入新的ug的情况下,能够快速地修改或者添加代码;
  • 可扩展性:在不修改或少量修改原有代码的情况下,可以通过扩展的方式添加新的功能代码;
  • 可复用性:尽量减少重复代码的编写,直接复用已有的代码;
  • 内聚性:模块内部元素的紧密程度,内聚性越高,那么模块独立性越好,可维护性,复用性也越高;
  • 耦合性:模块与模块之间的关联关系,耦合性越高,那么模块与模块之间关联越复杂,那么可维护性,复用性越差;

面向对象程序设计七大原侧:

单一职责原则SRP

        一个类或者模块只负责完成一个功能。通俗的讲,如果这个类包含了两个或多个业务不相干的功能,那么这个类的职责就不够单一,应该将它拆分成多个功能更加单一、粒度更细的类。单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又是最难运用的原则,需要设计人员发现类的不同职责并将其分离。

下面demo中的两个类的职责是划分出来的

package com.crj.principle;import java.util.List;public class UserInfo {private Long UserID;private String userName;private String phone;private List<Address> addresses;public void save(){System.out.println("用户信息");}
}
package com.crj.principle;public class Address {private String province;private String city;public void saveAddress(){System.out.println("保存地址信息");}
}

里氏替换原则LSP

        子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。换句话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法,如果重写父类方法,程序运行会发生出错概率。如果一定要用多态,那么父类可以设计成抽象父类或者接口。 所有可以使用父类的地方,必须能够透明的使用子类。

下面来看看一个例子: 

package com.crj.principle.t12;public class Bird {protected double runspeed;protected double flyspeed;public void setRunspeed(double runspeed) {this.runspeed = runspeed;}public void setFlyspeed(double flyspeed) {this.flyspeed = flyspeed;}public double canGetInstance(double distance){return distance/flyspeed;}
}

        我们定义了一个Bird类,如果子类A重写了Bird的setFlyspeed的方法并修改其功能(比如说不会飞的鸟我们返回一个0.0),那么就破环了里氏替换原则。这时候我们可以在Bird上面抽象一个父类出来并由新的不会飞的鸟类C去继承相应的父类来遵循里氏替换原则。


开闭原则OCP

        对扩展开放,对修改关闭。在程序需要修进行拓展的时候,不能去改原有的代码,实现一个热插拔的效果。想要达到这样的效果,我们需要使用接口和抽象类。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。

依赖倒置原则DIP

        模块之间要依赖抽象,不依赖实现类,要面向接口编程,不要面向实现编程。高层模块不应该直接依赖低层模块,这样就降低了客户端与实现模块间的耦合。简单来说我们封装模块的时候首先应该在接口或者抽象类定义相应功能方法,再用实现类来实现相应的具体功能,而不是直接用一个类就把所有的功能实现,在具体的功能实现时类只会调用相应接口对象的实现方法。

上面这段话感觉是不是比较难懂呢,我们看看这个例子:假设一个场景我们需要挑选不同的CPU和内存来组装计算机,我们当然可以只用类来实现功能,但是类中的CPU和内存类型写死了,如果又有新的选择无疑使得代码比较难以维护,因此我们可以根据依赖倒置原则来实现功能:

  •  首先定义两个接口

  •  接着定义各自的接口实现类

  • 定义对象类
package com.crj.principle.t3;import com.crj.principle.t3.cpu.CPU;
import com.crj.principle.t3.memory.Memory;public class Computer {private CPU cpu;private Memory memory;public Computer(CPU cpu, Memory memory) {this.cpu = cpu;this.memory = memory;}public Computer(){}public void startRun(){cpu.calculate();memory.storage();}
}
  • 测试类测试 
package com.crj.principle.t3;import com.crj.principle.t3.cpu.AmdCPU;
import com.crj.principle.t3.cpu.CPU;
import com.crj.principle.t3.memory.IMemory;
import com.crj.principle.t3.memory.Memory;public class Test {public static void main(String[] args) {CPU cpu = new AmdCPU();Memory memory = new IMemory();Computer com = new Computer(cpu,memory);com.startRun();}
}

主要看Computer类中我们执行startRun()方法时候并不需要知晓具体的产品(CPU、AMD)的类型,而是调用其接口类的类型方法即可实现。这降低了系统的耦合度,既符合依赖倒置原则也符合开闭原则


接口隔离原则 ISP

        Interface Segregation Principle,接口最小粒度设计。客户端不应该被迫依赖于它不使用的方法;一个类对另一个类的依赖应该建立在最小的接口上。一个类实现一个接口,就必须实现这个接口的所有抽象方法。如果接口设计的过于庞大的话,实现类就被迫实现不需要的抽象方法。简单来说其实就是在定义接口时要考虑到实现类不应该被迫实现接口中不需要的方法!解决方法就是按照接口功能粒度最小去设计接口。 


迪米特原则 LoD

        Law of Demeter,迪米特法则来自于1987年美国东北大学的一个名为Demeterl的一个研究项目,只跟朋友联系,不跟“陌生人”说话。如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。  


合成复用原则CRP

        Composite Reuse Principle,合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点:

  • 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
  • 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。

采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,优点如下:

  • 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
  • 对象间的耦合度低。可以在类的成员位置声明抽象抽象类或者接口)。

总结

        梳理完成,有关软件设计的知识荔枝就梳理到这里,接下来荔枝将会继续深入中间件的学习了,后面自己再抽时间回来看看笔记吧。知识是需要复盘的,也是需要总结和分享的~希望能帮助到有需要的小伙伴嘿嘿。

今朝已然成为过去,明日依然向往未来!我是荔枝,在技术成长之路上与您相伴~~~

如果博文对您有帮助的话,可以给荔枝一键三连嘿,您的支持和鼓励是荔枝最大的动力!

如果博文内容有误,也欢迎各位大佬在下方评论区批评指正!!!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux RPM JDK升级

以JDK1.8升级JDK17为例 上传jdk17安装包到linux服务器 检查jdk版本 rpm -qa|grep jdk 删除查询到的jdk rpm -e --nodeps jdk1.8-1.8.0_201-fcs.x86_64 删除完毕后安装新的jdk rpm -ivh jdk-17_linux-x64_bin.rpm 检查jdk版本 java -version

深入探讨基于python的SGBM参数影响效果

什么是SGBM SGBM&#xff08;Semi-Global Block Matching&#xff09;是一种用于计算双目视觉中视差&#xff08;disparity&#xff09;的半全局匹配算法&#xff0c;在OpenCV中的实现为semi-global block matching&#xff08;SGBM&#xff09;。它是基于全局匹配算法和局部匹…

Matlab 2016安装MinGW-w64-4.9.2

Matlab 2016安装MinGW-w64-4.9.2 项目需求&#xff1a;需要将matlab中的.m文件编译为cpp文件 .dll .h .lib。 我相信大家在对matlab2016安装MinGW-w64出现了各种各样的问题。如&#xff1a;4.9.2安装失败&#xff1b;安装了其他版本但是matlab检测不到&#xff0c;或者其他各种…

Matlab之DICOM(数字图像和通信医学)格式图像数据读取函数dicomread

一、DICOM是什么&#xff1f; DICOM是数字图像和通信医学格式的图像数据&#xff0c;在MATLAB中&#xff0c;可以使用dicomread函数读取DICOM格式的图像数据。 二、dicomread函数 使用方法如下&#xff1a; imageData dicomread(filename);其中&#xff0c;filename表示DI…

pdfjs解决ie浏览器预览pdf问题

pdfjs是一个js库&#xff0c;可以将pdf文件用canvas重新绘制&#xff0c;从而无需借助pdf读取插件就可以直接预览。 目前chrome内核的浏览器已内置pdf读取插件&#xff0c;但ie浏览器还没有。而我们最近在做的一个项目使用对象是医院&#xff0c;使用的浏览器竟然还是ie。所以我…

基础秘钥、公钥、地址的熟悉指南

1. 地址 0基础漫画式阅读&#xff1a;https://www.cnblogs.com/charlesblc/p/6130433.html 清晰详细的地址生成解释&#xff1a;比特币&#xff1a;账户私钥、公钥、地址的生成 - kumata - 博客园 (cnblogs.com) 对原理更详细解释&#xff1a;区块链技术核心篇之二&#xff…

在微信小程序上怎么实现多门店管理功能

微信小程序已经成为连接线上与线下的重要工具&#xff0c;尤其对于拥有多家门店的企业来说&#xff0c;通过微信小程序可以实现多门店管理&#xff0c;提高管理效率和用户体验。下面&#xff0c;我将为大家详细介绍如何在微信小程序上实现多门店管理功能。 一、确定多门店管理功…

【网络教程】记一次使用Docker手动搭建BT宝塔面板的全过程(包含问题解决如:宝塔面板无法开启防火墙,ssh,nginx等)

文章目录 准备安装安装宝塔面板开启ssh和修改ssh的密码导出镜像问题解决宝塔面板无法开启防火墙无法启动ssh设置密码nginx安装失败设置开机启动相关服务准备 演示的系统环境:Ubuntu 22.04.3 LTS更新安装/升级docker到最新版本升级docker相关命令如下# 更新软件包列表并自动升级…

没有软件怎么管理固定资产

在当今数字化的世界中&#xff0c;我们已经习惯了使用各种软件来管理我们的日常生活和工作。然而&#xff0c;当我们面临一个看似简单的问题——如何管理固定资产时&#xff0c;我们可能会感到困惑。那么&#xff0c;如果没有软件&#xff0c;我们该如何进行资产管理呢&#xf…

文章生成器免费版

你是否曾经陷入文案创作的困扰中&#xff1f;是不是为了撰写出优质的文章而煞费苦心&#xff1f;那么&#xff0c;如果我告诉你&#xff0c;现在有一种神奇的工具&#xff0c;可以为你解决这个问题&#xff0c;让你轻松地生成文章&#xff0c;你会不会感到兴奋呢&#xff1f;让…

Unity实现用WASD控制一个物体前后左右移动-小白课程01

1 根据业务逻辑搭建场景 02 根据业务写代码 using System.Collections; using System.Collections.Generic; using UnityEngine;//实现让被挂在的物体往前移动 //按下W键往前移动&#xff0c;按下S键往后移动 public class RoleMove : MonoBehaviour { public float myspe…

数据在内存中的存储——练习1

题目&#xff1a; int main() {int a[4] { 1,2,3,4 };int* ptrl (int*)(&a 1);int* ptr2 (int*)((int)a 1);printf("%x,%x"&#xff0c;ptr1[-1], *ptr2);return 0; } 思路分析&#xff1a; int* ptrl (int*)(&a 1); ptr1[-1] &a表示的是整个数…

winscope怎么实现user版本上导出方案设计探讨-千里马android framework车载车机手机系统开发

背景 在马哥给讲解怎么用winscope来分析各种闪黑&#xff0c;黑屏等问题后&#xff0c;很多买课的同学都开始使用这个工具用于实际公司的项目了&#xff0c;但是很多同学又开始发现有一个问题&#xff0c;那就发现在user版本的手机设备上发现无法抓取相关的winscope&#xff0…

Qt MinGW / MSVC

MinGW/MSVC的关系 MinGW / MSVC.dll / .lib / .a 的关系 MinGW / MSVC Qt 中有两种方式编译&#xff1a;一种是MinGW &#xff0c;另一种MSVC&#xff0c;是两种不同的编译器。 MinGW(Minimalist GNUfor Windows)&#xff0c;它是一个可自由使用和自由发布的Windows特定头文件…

PMP-项目启动过程组的重要性

一、什么是项目启动过程组 启动过程组包括定义一个新项目或现有项目的一个新阶段&#xff0c;授权开始该项目或阶段的一组过程。启动过程组的目的是&#xff1a;协调相关方期望与项目目的&#xff0c;告知相关方项目范围和目标&#xff0c;并商讨他们对项目及相关阶段的参与将如…

springboot导出(POI)

POI官方文档 引入依赖 <!--POI--><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId&…

Redis——其他数据类型介绍

概要介绍 Redis中有10种不同的数据类型。之前的blog中介绍了Redis中常见的五大数据类型&#xff1a;String&#xff0c;List&#xff0c;Hash&#xff0c;Set&#xff0c;ZSet。而Redis中还有许多其他的数据类型&#xff0c;一般在特定的场景中使用 Stream 首先介绍一下什么…

MySQL日常使用记录

1.时间 1.1.时间格式化 yyyy-MM-dd HH:mm:ss格式&#xff0c;如下&#xff1a; select date_format(now(), %Y-%m-%d %H:%i:%s) from dual;date_format函数是将date类型按照指定的格式转换成varchar类型 1.2.日期加减 当前天 1 天 select date_format(now(), %Y-%m-%d), …

C语言数组和指针笔试题(一)(一定要看)

目录 一维数组例题1例题2例题3例题4例题5例题6例题7例题8例题9例题10例题输出结果 字符数组例题1例题2例题3例题4例题5例题6例题7 一维数组 int a[] {1,2,3,4}; 1:printf("%d\n",sizeof(a)); 2:printf("%d\n",sizeof(a0)); 3:printf("%d\n",si…

继续上一个爬虫,所以说selenium加browsermobproxy

继续&#xff0c;书接上回&#xff0c;这次我通过jsrpc&#xff0c;也学会了不少逆向的知识&#xff0c;感觉对于一般的网站应该都能应付了。当然我说的是简单的网站&#xff0c;遇到那些混淆的&#xff0c;还有那种猿人学里面的题目&#xff0c;还是免谈了。那种需要的水平太高…