当前位置: 首页 > news >正文

设计模式与设计原则简介——及其设计模式学习方法

一、设计模式与设计原则的关系

        面向对象的分析设计有很多原则, 这些原则大多从思想层面给我们指出了面向对象分析设计的正确方向, 是我们进行面向对象分析设计时应该尽力遵守的准则。

        而设计模式已经是针对某个场景下某些问题的某个解决方案。也就是说这些设计原则是思想上的指导,而设计模式是实现上的手段,因此设计模式也应该遵守这些原则,换句话说,设计模式就是这些设计原则的一些具体体现。

二、为什么不重点讲解设计原则

        既然设计模式是设计原则的具体体现, 那么设计模式指导思想就是设计原则了,那为什么不重点讲解设计原则呢?

为什么不重点讲解设计原则
序号不重点讲解设计原则的原因
1设计原则是思想层面的指导,是高度概括的原则,指明的是设计上的大方向,但是它的具体实现不只是设计模式这一种形式。理论上来说,它可以指导很多不同的实现出来。
2设计原则只作为一种指导建议,在我们实际的软件开发中,基本上很难做到完全遵守,或多或少的会违反一些设计原则。我们还需要综合业务功能、实现的难度、系统性能、所需的空间与时间等多方面因素考虑。
3每种设计模式并不是单一的体现某个设计原则;很多设计模式是融合了很多设计原则思想,并不能特别强调设计模式对应某个设计原则;且每个设计模式在应用的时候也有很多考虑因素,不同场景下,突显的设计原则也可能是不一样的。
4设计模式本身就已经很复杂了,若在深入讲解说明设计原则,会造成没有重点,不能聚焦,不利于学习。

三、常见的六种面向对象设计原则

 3.1、常见的六种面向对象设计原则

常见的六种面向对象设计原则
序号常见的面向对象设计原则说明
1

单一职责原则【SRP】

(Single Responsibility Principle)

单一职责原则是指一个类应该仅有一个引起它变化的原因,这个变化原因就是职责
如果一个类有多个引起它变化的原因, 那么也就意味着这个类有多个职责,也就是说就是把多个职责耦合在一起了;这会造成职责的相互影响,可能一个职责的变化,会影响到其他职责的实现,甚至引起其他职责随着变化,这种设计是很脆弱的。

这个原则看起来是最简单和最好理解的, 但是实际上是很难完全做到的,难点在于如何区分“职责”;这是个没有标准量化的东西,哪些算职责、到底这个职责有多大的粒度、 这个职责如何细化等。;因此,在实际开发中,这个原则也是最容易违反的。

2开放关闭原则【OCP】
(Open-Closed Principle)

开放关闭原则是指一个类应该对扩展开放,对修改关闭。一般也被简称为开闭原则,开闭原则是设计中非常核心的一个原则。
 开闭原则要求:类的行为是可以扩展的,而且是在不修改已有代码的情况下进行扩展,也不必改动已有的源代码或者二进制代码。看起来好像是矛盾的,怎么样才能实现呢?实现开闭原则的关键就在于合理地抽象、分离出变化与不变化的部分, 为变化的部分预留下可扩展的方式(如:钩子方法或是动态组合对象等)。

        这个原则看起来也很简单, 但实际上一个系统中要全部做到遵守开闭原则,几乎是不可能的,也没必要。 适度的抽象可以提高系统的灵活性,使其可扩展、可维护,但是过度地抽象,会极大增加系统的复杂程度。 应该在需要改变的地方应用开闭原则就可以了, 而不用到处使用,从而陷入过度设计

3里氏替换原则【LSP】
(Liskov Substitution Principle)
里氏替换原则是指子类型必须能够替换掉它们的父类型;这很明显是一种多态的使用情况,它可以避免在多态的应用中,出现某些隐蔽的错误。

        事实上,当一个类继承了另外一个类, 那么子类就拥有了父类中可以继承下来的属性和操作;理论上来说,此时使用子类型去替换掉父类型,应该不会引起原来使用父类型的程序出现错误;但是,很不幸的是,在某些情况下是会出现问题的(如:若子类型覆盖了父类型的某些方法,或是子类型修改了父类型某些属性的值,那么原来使用父类型的程序就可能会出现错误,因为在运行期间,从表面上看,它调用的是父类型的方法,需要的是父类型方法实现的功能,但是实际运行调用的却是子类型覆盖实现的方法,而该方法和父类型的方法并不一样,于是导致错误的产生。

        从另外一个角度来说,里氏替换原则是实现开闭的主要原则之一:开闭原则要求对扩展开放,扩展的一个实现手段就是使用继承;而里氏替换原则是保证子类型能够正确替换父类型,只有能正确替换,才能实现扩展,否则扩展了也会出现错误。

4依赖倒置原则【DIP】
(Dependence Inversion Principle)
依赖倒置原则是指要依赖于抽象,不要依赖于具体类;要做到依赖倒置,典型的应该做到:
《1》高层模块不应该依赖于底层模块,二者都应该依赖于抽象。
《2》抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

很多人觉得,层次化调用的时候,应该是高层调用“底层所拥有的接口”,这是一种典型的误解。 事实上,一般高层模块包含对业务功能的处理和业务策略选择,应该被重用,是高层模块去影响底层的具体实现。因此, 这个底层的接口应该是由高层提出的,然后由底层实现的;也就是说底层的接口的所有权在高层模块,因此是一种所有权的倒置。
 倒置接口所有权,这就是著名的Hollywood(好莱坞) 原则: 不要找我们,我们会联系你。
5接口隔离原则【ISP】
(Interface Segregation Principle)
接口隔离原则是指不应该强迫客户依赖于他们不用的方法。
这个原则用来处理那些比较“庞大”的接口,这种接口通常会有较多的操作声明,涉及到很多的职责。客户在使用这样的接口的时候,通常会有很多他不需要的方法,这些方法对于客户来讲,就是一种接口污染,相当于强迫用户在一大堆“垃圾方法”中去寻找他需要的方法。因此,这样的接口应该被分离,应该按照不同的客户需要来分离成为针对客户的接口。这样的接口中,只包含客户需要的操作声明,这样既方便了客户的使用,也可以避免因误用接口而导致的错误。
分离接口的方式,除了直接进行代码分离之外,还可以使用委托来分离接口,在能够支持多重继承的语言中,还可以采用多重继承的方式进行分离。
6最少知识原则【LKP】
(Least Knowledge Principle)

最少知识原则是指只和你的朋友谈话。
 这个原则用来指导我们在设计系统的时候,应该尽量减少对象之间的交互,对象只和自己的朋友谈话,也就是只和自己的朋友交互,从而松散类之间的耦合。通过松散类之间的耦合来降低类之间的相互依赖,这样在修改系统的某一个部分的时候,就不会影响其他的部分,从而使得系统具有更好的可维护性。
那么究竟哪些对象才能被当作朋友呢? 最少知识原则提供了一些指导:
《1》当前对象本身。
《2》通过方法的参数传递进来的对象。
《3》当前对象所创建的对象。
《4》当前对象的实例变量所引用的对象。
《5》方法内所创建或实例化的对象。
总之,最少知识原则要求我们的方法调用必须保持在一定的界限范围之内,尽量减少对象的依赖关系。
7其他原则

除了上面提到的这六个常用原则,还有一些大家都熟知的原则如:
《1》面向接口编程。
《2》优先使用组合,而非继承。


也还有很多大家不是很熟悉的原则如:
《1》一个类需要的数据应该隐藏在类的内部。
《2》类之间应该零耦合,或者只有传导耦合(即:类之间要么没有关系,要么只使用另一个类的接口提供的操作)。
《3》在水平方向上尽可能统一地分布系统功能。

3.2、设计模式的学习方法

        在实际开发和设计中,要遵循简单设计的原则,不要为了模式而模式,不要过度设计,要在合适的地方应用合适的设计模式来解决问题。初学者尤其要注意, 因为刚学会一个东西, 总是跃跃欲试,急于一显身手,往往容易造成设计模式的误用。
  本设计模式专栏,需要反复研读实践。 因此,第一次阅读实践时,若发现有些不理解的内容也不要紧,可以在今后的学习和工作中,反复参阅本专栏,以加深对设计模式的理解,获取设计灵感,并把设计模式切实应用到实际项目中去。
 最后就是多结合实际的开发经验来思考,看看如何应用模式来解决实际问题、 如何把模式应用到实际的项目中去,再深入地思考模式的本质和设计思想,掌握模式的精髓,这样才能真正做到在实际开发中自如地应用设计模式。祝大家都学有所成。

http://www.xdnf.cn/news/1375291.html

相关文章:

  • 优选算法-常见位运算总结
  • uniapp中 ios端 scroll-view 组件内部子元素z-index失效问题
  • 基于 Node.js 的淘宝 API 接口开发:快速构建异步数据采集服务
  • 汽车电气系统的发展演进为测试带来了哪些影响?
  • DeFi协议Lombard能突破比特币生态原生叙事困境吗?
  • 图表可视化地理趋势-Telerik WPF Chart
  • 【Day 35】Linux-主从复制的维护
  • (LeetCode 面试经典 150 题 ) 637. 二叉树的层平均值(深度优先搜索dfs)
  • 亚马逊广告关键词排名提升的五大核心策略解析
  • java简单ssm(spring+springmvc+mybatis)框架结构demo
  • 大模型重构建筑“能耗基因“:企业如何用物联中台打响能源革命?
  • 手写MyBatis第36弹:MyBatis执行流程中SQL命令类型解析
  • 登录业务——密码重置与强制修改初始密码实现思路
  • 【微信小程序】分别解决H5的跨域代理问题 和小程序正常不需要代理问题
  • Coze用户账号设置修改用户名-后端源码
  • map|math
  • 腾讯位置商业授权微信小程序路线规划
  • 【开源工具】基于Flask与Socket.IO的跨平台屏幕监控系统实战(附完整源码)
  • 前端性能优化:从指标监控到全链路落地(2024最新实战指南)
  • 论文阅读:Gorilla: Large Language Model Connected with Massive APIs
  • 深度学习入门:神经网络基础知识
  • lesson47:Linux常用软件使用指南:远程连接、远程拷贝、Vim与Nginx
  • VESA时序检测模块设计verilog实现
  • Ubuntu 24 Server 如何设置无线网络
  • imx6ull-驱动开发篇45——Linux 下 SPI 驱动框架简介
  • d435i相机读取镜头内参和相对之间的外参
  • 艾体宝新闻 | 98%好评率!KnowBe4 连续5年蝉联第一,现开放免费钓鱼测试等你解锁
  • 内网应用如何实现外网访问?外地通过公网地址访问内网服务器的设置方法
  • 遗传算法:模拟自然选择的优化智慧
  • Spring Boot项目集成日志系统使用完整指南