面向对象复习_设计原则

设计模式

复用体现于:

  • 抽象化和继承:使概念和定义可复用
  • 多态:使实现和应用可复用
  • 抽象化和封装:可保持和促进系统的可维护性

开-闭原则OCP

软件组成实体应该是对扩展开放的,但是对修改是关闭的。

也就是:软件系统中包含的各种组件,例如模块(Modules)类(Classes)以及函数(Functions)等等,应该在不修改现有代码的基础上,引入新功能。 “开”,是允许对其进行功能扩展的; “闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。

解释:

  • 在设计一个软件的时候,应当使这个软件可以在不被修改的前提下扩展
  • 已有模块,尤其是最重要的抽象层模块不能动,需要保证稳定性和延续性
  • 可以扩展新模块:增加新行为,保证灵活性
    • 即:不允许更改的是系统的抽象层,允许扩展的是系统的实现层。

开-闭法则认为应该试图去设计出永远也不需要改变的模块。开闭原则的关键在于抽象化,用来给系统定义一个一劳永逸,不再更改的抽象设计,此设计允许有无穷无尽的行为在实现层被实现;同时,抽象层可以允许、支持所有扩展。

优点

  • 可复用性好:能够提高适应性 、 灵活性

    • 我们可以在软件完成以后,仍然可以对软件进行扩展,加入新的功能,非常灵活。因此,这个软件系统就可以通过不断地增加新的组件,来满足不断变化的需求。
  • 可维护性好:

    • 由于对于已有的软件系统的组件,特别是它的抽象底层不去修改,因此,我们不用担心软件系统中原有组件的稳定性,这就使变化中的软件系统有一定的稳定性和延续性。

一个软件系统的所有模块不可能都满足OCP,但是应该努力最小化这些不满足OCP的模块数量。

封装可变性原则
  • 考虑设计中什么可能会发生变化,考虑你允许什么发生变化而不让这一变化导致重新设计

  • 发现变化点,并封装之:

    • 一种可变性不应散落在代码的很多角落
    • 一种可变性不应当与另一种可变性混合在一起

里氏替换法则

使用指向基类(超类)的引用的函数,必须能够在不知道具体派生类(子类)对象类型的情况下使用它们。

解释:

  • 一个软件如果使用的是一个父类的话,如果把该父类换成子类,它不能察觉出父类对象和子类对象的区别

  • 也就是凡是父类适用的地方子类也适用

子类适用的地方不要求父类一定能适用

继承只有满足里氏代换原则才是合理的

小结
  • 里式替换法则(LSP)清楚地表明了Is a(是什么)关系全部都是与行为有关的。

  • 为了保持LSP,所有子类必须使用基类所期望的行为

  • 一个子类型不得具有比基类型更多的限制,可能这对于基类型来说是合法的,但是可能会因为违背子类型的其中一个额外限制,从而违背了LSP!

  • LSP保证一个子类总是能够被用在其基类可以出现的地方

依赖倒转原则

抽象不应当依赖于细节,细节应当依赖于抽象。

解释:

  • 传统的设计是抽象层依赖具体层
    • 传统的重用,侧重于具体层次的模块,比如算法、数据结构、函数库
    • 因此软件的高层模块依赖低层模块

高层依赖底层会带来很多问题:

  • 抽象层包含的是系统的业务逻辑和宏观的、战略性的决定,是必然性的体现

  • 具体层则含有与实现相关的算法和逻辑,以及战术性的决定,带有相当大的偶然性选择。具体层经常有变动,难免出现错误

实现方式:

  • 针对接口编程
  • 而不针对实现编程

不将变量声明为某个特定0的具体类的实例对象,而让其遵从抽象类定义的接口。实现类仅实现接口,不添加方法。

  • 任何变量都不应该持有一个指向具体类的指针或引用
  • 任何类都不应该从具体类派生
  • 任何方法都不应该覆写它的任何基类中已实现了的方法

优点:

  • Client不必知道其使用对象的具体所属类。
  • 一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。
  • 对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。
  • 松散耦合(loosens coupling)。
  • 增加了重用的可能性。
  • 提高了(对象)组合的机率,因为被包含对象可以是任何实现了一个指定接口的类。

组合复用原则

优先使用(对象)组合,而非(类)继承

组合与继承可以一起工作,但优先使用组合可以获得重用性与简单性更佳的设计,随后可以通过继承,以扩充可用的组合类集。

组合

优点:

  • 封装性:调用时仅能通过被包含对象的类接口对其进行访问,被包含对象的内部细节对外不可见封装性好
  • 耦合性:在实现上对象的相互依赖性比较小
  • 单一性:每一个类只专注于一项任务。
  • 动态性:通过获取指向其它的具有相同类型的对象引用,可以在运行期间动态地定义(对象的)组合。

缺点:

  • 数量角度:系统中的对象过多。
  • 容错角度:为了能将多个不同的对象作为组合块(composition block)来使用,必须仔细地对接口进行定义。
继承
  • (类)继承是一种通过扩展一个已有对象的实现,从而获得新功能的复用方法。
  • 泛化类(超类)可以显式地捕获那些公共的属性和方法。
  • 特殊类(子类)则通过附加属性和方法来进行实现的扩展

优点:

  • 易于实现:容易进行新的实现,因为其大多数可继承而来。
  • 易于修改:易于修改或扩展那些被复用的实现。

缺点:

  • 封装性: 破坏了封装性,因为这会将父类的实现细节暴露给子类,父类的内部细节对于子类可见
  • 当父类的实现更改时,子类也会随之更改。
  • 从父类继承来的实现将不能在运行期间进行改变。
Coad规则

仅当下列的所有标准被满足时,方可使用继承:

  • 子类表达了“是一个…的特殊类型”,而非“是一个由…所扮演的角色”
  • 子类的一个实例永远不需要转化(transmute)为其它类的一个对象
  • 子类是对其父类的职责(responsibility)进行扩展,而非重写或废除(nullify)
  • 子类没有对那些仅作为一个工具类(utility class)的功能进行扩展。

迪米特法则 (LoD)

又称最少知识原则:一个对象应该对其他对象尽可能少的了解。

狭义的迪米特法则

如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

“朋友”条件:
  • 当前对象本身(this)
  • 以参量形式传入到当前对象方法中的对象
  • 当前对象的实例变量直接引用的对象
  • 当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友
  • 当前对象所创建的对象

任何一个对象,如果满足上面的条件之一,就是当前对象的“朋友”;否则就是“陌生人”。

缺点:

  • 在系统里造出大量的小方法,这些方法仅仅是传递间接的调用,与系统的商务逻辑无关。
  • 遵循类之间的迪米特法则会是一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有直接的关联。但是,这也会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。

门面模式和调停者模式实际上就是迪米特法则的应用。

广义的迪米特法则
  • 优先考虑将一个类设置成不变类。
  • 尽量降低一个类的访问权限。
  • 尽量降低成员的访问权限。
  • 谨慎使用序列化(Serializable)。

接口隔离原则 (ISP)

  • 使用多个专门的接口比使用单一的总接口好。
  • 一个类对另一个类的依赖性应建立在最小的接口上。

一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

单一职责原则

不要存在多于一个导致类变更的原因。

通俗的说,即一个类只负责一项职责。

解释:
如果一个类承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。

而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则

此原则的核心就是解耦和增强内聚性

问题由来:
类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。
解决方案:
遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。

职责扩散

因为某种原因,职责P被分化为粒度更细的职责P1和P2。

如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,分别负责P1、P2两个职责。
但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。(这样做的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,在未来可能会扩散为P1,P2,P3,P4……Pn。所以记住,在职责扩散到我们无法控制的程度之前,立刻对代码进行重构。)

参考链接

https://www.cnblogs.com/geek6/p/3951677.html
https://www.cnblogs.com/tongkey/p/7170826.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值