zoukankan      html  css  js  c++  java
  • 面向对象七大设计原则

    面向对象七大原则

    开闭原则

    对扩展开放,对修改关闭

    由Bertrand Meyer提出的开闭原则(Open Closed Principle)是指,软件应该对扩展开放,而对修改关闭。这里的意思是在增加新功能的时候,能不改代码就尽量不要改,如果只增加代码就完成了新功能,那是最好的。

    里氏替换原则

    继承必须确保超类所拥有的的性质在子类中仍然成立

    里氏替换原则是Barbara Liskov提出的,这是一种面向对象的设计原则,即如果我们调用一个父类的方法可以成功,那么替换成子类调用也应该完全可以运行。

    • 第一种定义,也是最正宗的定义:

      If for each object o1 of type S there is an object o2 of
      type T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 is
      substituted for o2 then S is a subtype of T.

      如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。

    • 第二种定义:

      Functions that use pointers or references to base classes must be able to use
      objects of derived classes without knowing it.

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

    第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

    依赖倒置原则

    面向接口编程,不要面向实现编程

    依赖倒置原则的原始定义是:

    High level modules should not depend upon low level modules.Both should depend upon
    abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

    翻译过来,包含三层含义:

    • 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
    • 抽象不应该依赖细节;
    • 细节应该依赖抽象。

    高层模块和低层模块容易理解,每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块。那什么是抽象?什么又是细节呢?在Java语言中,抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点就是可以直接被实例化,也就是可以加上一个关键字new产生一个对象。依赖倒置原则在Java语言中的表现就是:

    • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过
      接口或抽象类产生的;

    • 接口或抽象类不依赖于实现类;

    • 实现类依赖接口或抽象类。

    更加精简的定义就是“面向接口编程”——OOD(Object-Oriented Design,面向对象设计)的精髓之一。

    单一职责原则

    控制类的粒度大小、将对象解耦、提高其内聚性

    单一职责原则的定义是:应该有且仅有一个原因引起类的变更。

    总结一下单一职责原则有什么好处:

    • 类的复杂性降低,实现什么职责都有清晰明确的定义;
    • 可读性提高, 复杂性降低,那当然可读性提高了;
    • 可维护性提高,可读性提高,那当然更容易维护了;
    • 变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

    注意 单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。

    对于接口,我们在设计的时候一定要做到单一,但是对于实现类就需要多方面考虑了。生搬硬套单一职责原则会引起类的剧增,给维护带来非常多的麻烦,而且过分细分类的职责也会人为地增加系统的复杂性。本来一个类可以实现的行为硬要拆成两个类,然后再使用聚合或组合的方式耦合在一起,人为制造了系统的复杂性。所以原则是死的,人是活的,这句话很有道理

    接口隔离原则

    要为各个类建立它们需要的专用接口

    接口分为两种:

    • 实例接口(Object Interface),在Java中声明一个类,然后用new关键字产生一个实
      例,它是对一个类型的事物的描述,这是一种接口。比如你定义Person这个类,然后使用
      Person zhangSan=new Person()产生了一个实例,这个实例要遵从的标准就是Person这个
      类,Person类就是zhangSan的接口。疑惑?看不懂?不要紧,那是因为让Java语言浸染的时间
      太长了,只要知道从这个角度来看,Java中的类也是一种接口。

    • 类接口(Class Interface),Java中经常使用的interface关键字定义的接口。
      主角已经定义清楚了,那什么是隔离呢?它有两种定义,如下所示:

    1. Clients should not be forced to depend upon interfaces that they don't use.(客户端不应该依赖它不需要的接口。)

    2. The dependency of one class to another one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上。)

    新事物的定义一般都比较难理解,晦涩难懂是正常的。我们把这两个定义剖析一下,先说第一种定义:“客户端不应该依赖它不需要的接口”,那依赖什么?依赖它需要的接口,客户端需要什么接口就提供什么接口,把不需要的接口剔除掉,那就需要对接口进行细化,保证其纯洁性;再看第二种定义:“类间的依赖关系应该建立在最小的接口上”,它要求是最小的接口,也是要求接口细化,接口纯洁,与第一个定义如出一辙,只是一个事物的两种不同描述。

    我们可以把这两个定义概括为一句话:建立单一接口,不要建立臃肿庞大的接口。再通俗一点讲:接口尽量细化,同时接口中的方法尽量少。看到这里大家有可能要疑惑了,这与单一职责原则不是相同的吗?错,接口隔离原则与单一职责的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。例如一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,并且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外通过文档约束“不使用的方法不要访问”,按照单一职责原则是允许的,按照接口隔离原则是不允许的,因为它要求“尽量使用多个专门的接口”。专门的接口指什么?就是指提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端访问。

    迪米特法则

    只与你的直接朋友交谈,不跟“陌生人”说话

    迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least KnowledgePrinciple,LKP),虽然名字不同,但描述的是同一个规则:一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没关系,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关心。

    迪米特法则还有一个英文解释是:Only talk to your immediate friends(只与直接的朋友通信。)什么叫做直接的朋友呢?每个对象都必然会与其他对象有耦合关系,两个对象之间的耦合就成为朋友关系,这种关系的类型有很多,例如组合、聚合、依赖等。下面我们将举例说明如何才能做到只与直接的朋友交流。

    迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。其要求的结果就是产生了大量的中转或跳转类,导致系统的复杂性提高,同时也为维护带来了难度。读者在采用迪米特法则时需要反复权衡,既做到让结构清晰,又做到高内聚低耦合。

    合成复用原则

    合成复用原则又称为组合/聚合复用原则(Composition/Aggregate Reuse Principle, CARP),其定义如下:

    合成复用原则(Composite Reuse Principle, CRP):尽量使用对象组合,而不是继承来达到复用的目的。

    合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合聚合关系(关联关系),少用继承

    在面向对象设计中,可以通过两种方法在不同的环境中复用已有的设计和实现,即通过组合/聚合关系或通过继承,但首先应该考虑使用组合/聚合,组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

    通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。

    保持对优秀的热情
  • 相关阅读:
    5分钟快速入门angular2.0
    手把手教你书写对话框(构造函数&原型模式)
    JavaScript函数
    Javascript 循环
    javascript
    vue2.0 axios post请求传参问题(ajax请求)
    19.8.13第二天
    19.8.12 第一天的学习
    C#设计模式--简单工厂模式
    C#设计模式--单例模式
  • 原文地址:https://www.cnblogs.com/luckforefforts/p/13692494.html
Copyright © 2011-2022 走看看