设计模式——面向对象的设计原则

shanzm-2020年3月31日 20:17:27

0. UML

统一建模语言(Unified Modeling Language,UML)是用来设计软件蓝图的可视化建模语言。html

能够参考统一建模语言编程

于此不详述,仅展现使用Visual Studio自动生成的类图样式设计模式

须要说明的是,VS中生成的类图样式和通常通用的UML是有一些区别的,可是也就仅仅能够称之为风格不一样,其总体是同样的架构

  • :蓝色方框,上部分为类名和该类的父类,下部分为类中成员,抽象类类名为斜体且方框为虚线.net

    通用的UML中,访问修饰符private(“-”),public(“+”),在VS中直接用单词表示,无需多虑设计

  • 接口:绿色方框,上部分为接口名,下部分为接口成员(方法,属性,事件)htm

  • 聚合关系:使用金色的实线加箭头链接对象

    一个类中拥有另外一个类的类型的属性,默认是显示在属性框中,右键->显示为关联,则能够显示blog

  • 继承关系:子类经过实线加箭头指向父类继承

  • 实现接口:实现类的上方使用实线链接一个圆形,并标注实现的接口名(这种表示方法称之为:棒棒糖表示法)

    通用的UML中,实现接口通常是使用虚线加箭头指向接口

示例:

图中描述的是:
Person类为抽象类,有三个属性,派生了Student类和Teacher类

ILivable为接口,有两个方法,Student和Teacher类都实现了该接口

Student类中有一个Teacher类型的属性teacher,同时还有一个Class类型的属性@class

Teacher类中有一个List<Student>类型的属性students,同时还有一个Class类型的属性@class

Class类中有List<Student>类型的属性students,同时还有List<Teacher>类型的属性teachers



1. 开闭原则

是什么?
开闭原则(Open Closed Principle,OCP):软件实体应该对扩展开放,对修改关闭。

即软件实体尽可能在不修改软件源代码的状况下进行扩展

这里的软件实体主要是指:模块、类、接口、方法

它也是其余面向对象设计原则的基础,也是面向对象的程序设计的终极目标。

怎么作?
在面向对象设计中,能够经过“抽象约束、封装变化”来实现开闭原则,即经过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。

为何?
当须要对软件进行扩展的时候,咱们不须要修改抽象层,只须要从抽象类中派生一个实现类便可,从而实现软件具备必定的稳定性和延续性。

开闭原则是面向对象程序设计的终极目标,而里氏转换原则和依赖倒置原则都是实现开闭原则的方式。

这句话你品,你仔细品!



2. 里氏替换原则

是什么?
里氏替换原则(Liskov Substitution Principle,LSP)父类对象出现的地方均可以使用子类对象替换。

换言之,一个父类对象引用能够指向其子类对象。

怎么实现一个父类对象引用能够指向其子类对象呢?那就是遵循——子类能够扩展父类的功能,可是不能改变(重写)父类的原有功能

怎么作?
运用里氏原则时,尽可能将须要扩展的类或是存在变化的类设计为抽象类或是接口,并将其做为基类使用,在编程的时候尽可能对基类对象进行编程。

为何?
在程序中声明基类引用,而该引用指向一个子类对象,这样能够随时替换不一样的子类对象,从而实现不一样的功能,而不须要修改那些使用该基类对象的代码。

以前说过,子类能够扩展父类的功能,可是不要改变父类的原有功能,就是由于在调用一个父类对象中的方法使用,而此时我更换一个其子类对象,原则上是彻底能够的,可是如果子类中对其父类中的方法重写了,并且碰巧这里调用这个父类中的方法,则程序会出现异常!



3. 依赖倒置原则

是什么?
依赖倒置原则(Dependence Inversion Principle,DIP)高层模块不该该依赖低层模块,二者都应该依赖其抽象;抽象不该该依赖细节,细节应该依赖抽象。

怎么作?
针对接口编程,而不是针对实现编程。

  • 每一个类尽可能提供接口或抽象类,或者二者都具有。
  • 变量的声明类型尽可能是接口或者是抽象类
  • 任何类都不该该从具体类派生。
  • 使用继承时尽可能遵循里氏替换原则。

为何?
在软件设计中,细节具备多变性,而抽象层则相对稳定,所以以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类



4. 单一职责原则

是什么?
单一职责原则(Single Responsibility Principle,SRP)又称单一功能原则,一个类应该有且仅有一个引发它变化的缘由,不然类应该被拆分

换言之,一个类只负责一个功能领域中的相应职责

怎么作?
发现并将类的不一样职责分离,再封装到不一样的类或模块中

为何?
单一职责是实现高内聚,低耦合的指导方针

在面向对象的程序设计中,若是一个类承担的职责越多,则其能够被复用的可能性就越小。一个类承担多个职责就是将多个职责耦合在一块儿,当其中的一个职责发生改变的时候,可能会影响到其余职责的功能。



5. 接口隔离原则

是什么?
接口隔离原则(Interface Segregation Principle,ISP)将臃肿庞大的接口拆分红更小的和更具体的接口,让接口中只包含客户感兴趣的方法。

换言之,不要使用单一的总接口,使用具体的有针对性的小接口。

怎么作?
接口尽可能要小,每一个接口承担相对独立的功能。

为何?
面向对象中,实现一个接口,则必须实现接口中的全部方法,如果接口过于的庞大,则使用起来不方便,并且可能当前对象只须要该接口中的部分功能。



6. 迪米特法则

是什么?
迪米特法则(Law of Demeter,LoD)又叫做最少知识原则(Least Knowledge Principle,LKP)“只与你的直接朋友交谈,不跟'陌生人'说话”

换言之,一个软件实体应当尽量少地与其余实体发生相互做用。

其含义是:若是两个软件实体无须直接通讯,那么就不该当发生直接的相互调用,能够经过第三方转发该调用。其目的是下降类之间的耦合度,提升模块的相对独立性。

怎么作?

  1. 从依赖者的角度来讲,只依赖应该依赖的对象。
  2. 从被依赖者的角度说,只暴露应该暴露的方法。

典型应用:中介者模式

为何?
下降了类之间的耦合度,提升了模块的相对独立性,从而提升了类的可复用率和系统的扩展性。

可是严格的遵循迪米特法则,则可能会出现大量的中介者类,从而增长了系统的复杂性,下降了模块之间通讯的效率。

因此采用迪米特法则须要权衡利弊,在确保低耦合的状况下,避免增长系统的复杂性



7. 合成复用原则

是什么?
合成复用原则(Composite Reuse Principle,CRP)它要求在软件实体复用时,要尽可能先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

换言之,尽可能使用对象组合,而不是使用继承来达到复用的目的。

类与类之间的关系是一种结构性的关系,称之为关联关系,包括:单项关联,双向关联,自关联,聚合关系,组合关系

  • 聚合关系:即部分与总体的关系(UML中使用空心的菱形表示),好比计算机包括鼠标,可是鼠标能够单独存在
  • 组合关系:也是部分与总体的关系,可是其中的部分与总体具备统一的生命周期(UML中使用实心黑色菱形表示),好比头和嘴,没有头也就没有了嘴

怎么用?
合成复用原则是经过将已有的对象归入新对象中,做为新对象的成员对象来实现的,新对象能够调用已有对象的功能,从而达到复用。

新对象经过委托的方式调用已有对象中的方法。(这也是委托的意义

为何?
继承关系破坏了类的封闭性,父类对子类是透明的,父类中的成员都暴露给子类(这种复用称之为“白箱”复用)

子类与父类的耦合度高。父类的实现的任何改变都会致使子类的实现发生变化,这不利于类的扩展与维护。



总结

  • 我我的以为这些所谓的设计原则,包括全部的设计模式都是为了如下目的:

    • 实现代码模块的解耦,实现高内聚,低耦合!----不要牵一发而动全身

    • 加强代码的可扩展性,实现程序的延续性!----不要没法实现后续新需求

    • 提升代码的鲁棒性!----不要一修改,程序就崩溃

  • 7种设计原则总结

名称 定义 使用频率
开闭原则( Open Closed Principle,OCP ) 软件实体应该对扩展开放,对修改关闭 ★★★★★
里氏替换原则(Liskov Substitution Principle,LSP) 父类对象出现的地方均可以使用子类对象替换 ★★★★★
依赖倒置原则(Dependence Inversion Principle,DIP) 高层模块不该该依赖低层模块,二者都应该依赖其抽象;抽象不该该依赖细节,细节应该依赖抽象 ★★★★★
单一职责原则(Single Responsibility Principle,SRP) 一个类只负责一个功能领域中的相应职责 ★★★★☆
接口隔离原则(Interface Segregation Principle ,ISP) 不要使用单一的总接口,而是使用具体的有针对性的小接口 ★★☆☆☆
迪米特法则(Law of Demeter, LoD) 一个软件实体应当尽量少地与其余实体发生相互做用 ★★★☆☆
合成复用原则(Composite Reuse Principle,CRP) 尽可能使用对象组合,而不是使用继承来达到复用的目的 ★★★★☆

注:该表来源于《设计模式实训教程(第二版)-刘伟》



参考

本文主要就是如下连接的阅读笔记,详细能够阅读如下内容:

C语言中文网:设计模式

《设计模式实训教程(第二版)-刘伟》

相关文章
相关标签/搜索