设计模式与设计原则简介(一)详解

电脑杂谈  发布时间:2019-05-20 18:14:29  来源:网络整理

oop原则_ood与oop_oop编程

我们知道对于很多数学问题,经常会有多种不同的解法

而且这其中可能会有一种比较通用简便高效的方法

我们在遇到类似的问题或者同一性质的问题时,也往往采用这一种通用的解法

将话题转移到程序设计中来

对于软件开发人员, 在软件开发过程中, 面临的一般问题的解决方案就是设计模式(准确的说是OOP中)

当然,如同数学的解题思路一样,设计模式并不是公式一样的存在

设计模式(Design pattern)代表了最佳的实践

是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的宝贵经验

是解决问题的思路

总之,设计模式是一种思想,思想,思想。

随着面向对象编程语言的发展,以及软件开发规模的不断扩大

编写良好的OOP程序变得困难,而编写可复用的OOP程序则更是困难

在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides

书名:快乐数学填色书:10以内加减综合训练作者:瑞雅卡通 编丛 书 名:出 版 社:汕头大学出版社isbn:9787811209358出版时间:2010-09-01版次:1页数:24装帧:平装开本:大16开所属分类:图书 > 少儿 > 幼儿启蒙图书 > 少儿 > 3-6岁印刷时间:2010-09-01纸张:胶版纸印次:1正文语种:中文附件:套装数量:0读者对象:定 价:¥8.00。中青记者继续以高校教师的角色向客服咨询如何出合著,客服则给记者抛出3本教材的名称、出版社信息,供记者选择,并向记者保证,“能接就肯定能出版”,需先确定书籍名称、字数、出版社、出版时间等信息,再签订合同,付全款一半,安排出版,新闻出版总署查图书在版编目cip(仅独著作者或者合著主编可查到),付尾款。记者继续以高校教师的角色向客服咨询如何出合著,客服则给记者抛出3本教材的名称、出版社信息,供记者选择,并向记者保证,“能接就肯定能出版”,需先确定书籍名称、字数、出版社、出版时间等信息,再签订合同,付全款一半,安排出版,新闻出版总署查图书在版编目cip(仅独著作者或者合著主编可查到),付尾款。

该书首次提到了软件开发中设计模式的概念。

四位作者合称 GOF(四人帮,全拼 Gang of Four)

这就是设计模式四个字的起源

当然,即使在这本书出版之前,肯定也已经有很多有经验的OOP程序员已经在使用自己的经验(设计模式)了

但是这本书将OOP的设计经验作为设计模式记录下来

使我们能够更加简单方便的复用成功的设计经验和体系结构

"随着面向对象编程语言的发展,以及软件开发规模的不断扩大

编写良好的OOP程序变得困难,而编写可复用的OOP程序则更是困难"

设计模式的起源, 正是需要设计模式的根本原因

借助于设计模式,可以更好地实现代码的复用,增加可维护性

怎么才能更好地实现代码复用呢?

面向对象有几个原则:

(2)开闭原则:软件实体应当对扩展开放,对修改关闭。- 开闭原则:软件实体应当对扩展开放,对修改关闭。2.开-闭原则(open-closed principle,ocp):一个软件实体对扩展开放,对修改关闭。

即软件实体应尽量在不修改原有代码的情况下进行扩展

ood与oop_oop编程_oop原则

在开闭原则的定义中,软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类

不修改已有代码的基础上扩展系统的功能的形式,就是符合开闭原则的

开闭原则的关键是抽象

比如,一个方法中

if(){

//...

}else if(){

//...

}

如果新增加一个逻辑功能点,则需要增加新的else 或者 else if ,势必修改了已有代码

而如果面向抽象的接口或者抽象类进行编程,扩展增加新的功能,只需要传递新的子类即可,原有的代码功能不会有任何的修改

再比如

实际项目开发的时候,我们会把一些配置写入到配置文件中,而不是"硬编码"到代码中

修改参数设置的时候,源代码无需更改,这也是符合开闭原则

开闭原则作为根本原则,并不限定某种具体场景,只要是符合了这一含义,就是符合开闭原则

总之,开闭原则就是别因为新增功能扩展改(老)代码

开闭原则是根本纲领,它是面向对象设计的终极目标

除了根本原则另外还有六大原则 , 则可以看做是开闭原则的实现方法

单一职责原则 (Single Responsiblity Principle SRP)

一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因

单一职责的原则很简单,就是一个实体(一个类或者一个功能模块)不要承担过多的责任

承担了过多的责任也就意味着多个功能的耦合

堆积木时, 到底是一块积木比较容易利用, 还是多块积木拼接起来的"一大块" 更容易利用? 结果显而易见

而且,承担了过多的责任,也就是可能会因为多个原因修改这段代码

随之而来的是不稳定性以及维护成本的增加,也就是将会有多个原因引起他变化

单一职责原则的根本在于控制类的粒度大小

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

里氏替换原则是以提出者 Barbara Liskov 的名字命名的

ood与oop_oop原则_oop编程

定义:

如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2

使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化

那么类型 T2 是类型 T1 的子类型

定义一:如果对每一个类型为t1的对象o1,都有类型为t2的对象o2,使得以t1定义的所有程序p在所有的对象o1都被替换成o2时,程序p的行为没有发生变化,那么类型t2是类型t1的子类型。1.如果对每一个类型为t1的 对象o1,都有类型为t2的对象o2,使得以t1定义的所有程序p在所有的对象o1都替换成o2时,程序p的行为没有发生变化,那么类型t2是类型t1的子类型。图2所示为4输入与非门(ttl)电路,图中d1~d4构成四输入二极管与门,t1、t2构成射级耦合双稳态触发器(施密特触发器),t3、d5是射级跟随器,完成电平转移,t4、t5、t6构成推拉式输出电路。

那么T2 是T1的子类型

再简单的概述就是:

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

透明也就意味着不感知,不受任何影响

听起来好像很自然的就可以做到

假如子类覆盖了父类的方法呢?假如子类覆盖了父类的方法并且改变了父类方法的原有功能逻辑呢?

比如,原来传递来两个参数进行加法运算,子类覆盖后,进行减法运算,会发生什么?

里氏代换原则的根本,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常

想要透明的使用子类,满足里氏替换原则

需要注意应该尽可能的将父类设计为抽象类或者接口

让子类继承父类或实现父接口,并实现在父类中声明的方法,这样可以做到满足开闭原则

子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法,也就是父类定义,子类实现

而且,子类不应该破坏父类的契约,也就是不能更改原有的方法的逻辑含义

里氏替换是继承复用的基石,只有当子类可以替换父类,且软件单位的功能不受到影响时

父类才能真正被复用,而子类也能够在基类的基础上增加新的行为

里氏代换原则是对开闭原则的补充。

实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范

依赖倒转原则(Dependency Inversion Principle, DIP)

抽象不应该依赖于细节,细节应当依赖于抽象; 换言之,要针对接口编程,而不是针对实现编程

也就是使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不是使用具体的类

在需要时,将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中

在引入抽象层后,程序中尽量使用抽象层进行编程, 系统将具有很好的灵活性 并且将具体类写在配置文件中

如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件

ood与oop_oop原则_oop编程

而无须修改原有系统的源代码 , 扩展系统的功能无需修改原来的代码,满足开闭原则的要求

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

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

根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可

接口隔离根本在于不要强迫客户端程序依赖他们不需要使用的方法

合成/聚合复用原则(Composite/Aggregate Reuse Principle,C/ARP)

复用一个类有两种常用形式,继承和组合

尽量使用对象组合,而不是继承来达到复用的目的,因为继承子类可以覆盖父类的方法,将细节暴露给子类

而且会建立强耦合关系,是一种静态关系,不能再运行时更改等等弊端

个人建议,对于继承的态度是不滥用,不弃用,带着脑子用!

迪米特法则(Principle of Least Knowledge,PLK,也叫最小知识原则)

一个软件实体应当尽可能少地与其他实体发生相互作用

也就是一个对象应当对其他对象有尽可能少的了解

再设计系统时,应该尽可能的减少对象之间的交互

有一个形象的说法"不要和“陌生人”说话、只与你的直接朋友通信"

下面这些一般被认为是朋友

(1) 当前对象本身(this);

(2) 以参数形式传入到当前对象方法中的对象;

(3) 当前对象的成员对象;

(4) 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;

(5) 当前对象所创建的对象

其实也仍旧是"不要和其他对象有过多的联系",只在必要的时候与外界进行联系

"不要和“陌生人”说话、只与你的直接朋友通信" 就能够最大程度的降低耦合性

类之间的耦合度越低,就越有利于复用

如果两个对象之间不是必须要直接通信,那么这两个对象就可以不发生任何直接的相互作用

而是可以通过第三者转发这个调用,通过引入第三者将耦合度降低

开闭原则

软件实体应该对扩展开放,对修改关闭。

ood与oop_oop编程_oop原则

开闭原则是设计原则的核心原则,其他的设计原则都是开闭原则表现和补充。实现开闭原则的方法就是抽象。

单一职责原则

一个类应该只承担一种责任。

里氏替换原则

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

依赖倒置原则

面向抽象编程,不要面向具体编程。

接口隔离原则

使用专门的接口,而不是大而全统一的接口,不要强迫客户端程序依赖不需要的方法。oop原则

聚合/组合复用原则

如果可以,应该使用组合而不是继承来达到代码复用的目的。

迪米特法则:

软件实体之间应该做到最少的交互。不要和陌生人说话。oop原则

设计原则是指导思想,将规则落实到具体的类/接口的设计、功能逻辑的划分上,可以转化成以下要求

所有的要求都有一个前提:如果可以,应该优先考虑,尽可能的

设计原则是软件开发过程中,前人以“高内聚,低耦合” “提高复用性”“提高可维护性”为根本目标

在实践中总结出来的经验,进而演化出来的具体的行为准则

就好似要做“好”一件事情,那么“好”的标准是什么?

按照经验总结归纳出来的一些“好”的标准,就是程序设计中的设计原则

设计原则是站在不同的维度与角度思考问题的, 他们的根本目的是相同的

本质都是为了设计一个“易维护、可复用、高内聚低耦合”的程序

比如单一职责原则与接口隔离原则,本质都是要职责专一

类提供单一的功能的实现,接口不要有大而全的功能约定

职责专一就能降低耦合,就更有可能被复用

使用组合而不是继承可以避免子类对父类的修改这种情况也就符合了里氏替换原则,也就符合了开闭原则

spring 主要思想ioc(控制反转) 是core的核心部分,aop(面向切面编程),其中ioc由di(依赖注入)的思想实现,aop是oop(面向对象)的一种延伸,spring可以降低程序组建之间的耦合度。(3)依赖倒转原则:面向接口编程。依赖倒置原则:面向抽象编程,不要面向具体编程。

“易维护、可复用、高内聚低耦合”是目标

设计原则是为了达到目标的具体规则

而设计模式则是符合设计规则的具体的类/接口的设计解决方案

也就是设计原则的具体化形式

更准确的说,一个设计良好的程序应该遵循的是设计原则,而并非一定是某个设计模式

所有的原则都是指导方针,而不是硬性规则


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-100104-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...