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

    面向对象设计原则是设计模式的灵魂。

    换句话说,设计原则与设计模式更重要。设计模式是我们在解决问题的过程总结出来的,而总结他们的理论基础就我下面的设计原则:

    在学习面向对象设计原则之前,我们要对封装、继承、多态思想有足够的了解,对抽象类和接口也要有足够的编码能力。

     1. 单一职责原则(SRP)

    就一个类而言,应该仅有一个引起它变化的原因。

    一个类被修改的几率很大,因此应该专注于单一的功能,将不同的职责分配给不同的类,使单个类的职责尽量单一,就隔离了变化,这样他们也不会互相影响了。 

    如果你把多个功能放在同一个类中,功能之间就形成了关联,改变其中一个功能,有可能中止另一个功能,噩梦也就开始了。

    2. 开放—封闭原则(OCP) 

    软件实体(类、模块、函数等)对扩展开放的,但是对修改是关闭的。意思是你可以增加新的类,但是不要修改原来的类。

    根据开闭原则,在设计一个软件系统模块(类,方法)的时候,应该可以在不修改原有的模块(修改关闭)的基础上,能扩展其功能(扩展开放)。

    3. 依赖倒置原则(DIP)

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

    解释一下:

    高层模块和低层模块容易理解,每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块。

    抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点就是可以直接被实例化,也就是可以加上一个关键字new产生一个对象。依赖倒置原则就是:

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

    依赖倒置原则的核心思想是面向接口编程

    在实际编程中,我们一般需要做到如下3点:

    • 低层模块尽量都要有抽象类或接口,或者两者都有。
    • 变量的声明类型尽量是抽象类或接口。
    • 使用继承时遵循里氏替换原则。

    4. 接口隔离原则(ISP) 

    客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上

    可以理解为:建立一个简单单一接口,不要建立臃肿庞大的接口,接口尽量细化,接口中的方法尽量少。

    提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端访问。

    接口是我们设计时对外提供的契约,通过分散定义多个接口,可以预防未来变更的扩散,提高系统的灵活性和可维护性

    不要强迫客户依赖它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

    接口隔离原则的意思就是:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口当中.

    分离接口的两种实现方法:

    1.使用委托分离接口。(Separation through Delegation)

    2.使用多重继承分离接口。(Separation through Multiple Inheritance)


    5. 里氏替换原则(LSP) 
    子类型必须能够替换掉它们的基类型。所有引用基类(父类)的地方必须能透明地使用其子类的对象。

    在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象

    里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:

    1.在任何父类出现的地方都可以用他的子类来替代(子类应当可以替换父类并出现在父类能够出现的任何地方)子类必须完全实现父类的抽象方法。在类中调用其他类时务必要使用抽象类或接口,如果不能使用抽象类或接口,则说明类的设计已经违背了LSP原则。

    2.子类可以有自己的个性。子类当然可以有自己的行为和外观了,也就是方法和属性

    3.覆盖或实现父类的方法时输入参数可以被放大。即子类可以重载父类的方法,但输入参数应比父类方法中的大,这样在子类代替父类的时候,调用的仍然是父类的方法。即以子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松。

    4.覆盖或实现父类的方法时输出结果可以被缩小。

     

    原则六:合成复用原则(组合/聚合复用原则)(CRP:Composite Reuse Principle)

    核心思想:

    尽量使用对象组合,而不是继承来达到复用的目的。该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。

    合成:表示一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样,打个比方:人有两个胳膊,胳膊和人就是部分和整体的关系,人去世了,那么胳膊也就没用了,也就是说胳膊和人的生命周期是相同的

    聚合:表示一种弱的拥有关系,体现的是A对象可以包含B对象,但是B对象并不是A对象的一部分,打个比方:人是群居动物,所以每个人属于一个人群,一个人群可以有多个人,所以人群和人是聚合的关系

    为什么不推荐通过继承来实现复用:

    1) 对象的继承关系在编译时就定义好了,所以无法在运行时改变从父类继承的子类的实现,没有足够的灵活性。

    2)通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类。

    3)子类的实现和它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化

    4)当你复用子类的时候,如果继承下来的实现不适合解决新的问题,则父类必须重写或者被其它更适合的类所替换

    由于组合或聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所以这种复用又称为“黑箱”复用。

    相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性地调用成员对象的操作;合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。

     一般而言,如果两个类之间是“Has-A”的关系应使用组合或聚合,如果是“Is-A”关系可使用继承。"Is-A"是严格的分类学意义上的定义,意思是一个类是另一个类的"一种";而"Has-A"则不同,它表示某一个角色具有某一项责任。

    复用的种类:

    1.继承

    2.合成聚合

    注:在复用时应优先考虑使用合成聚合而不是继承

    原则七:迪米特原则(LOD:Law of Demeter)

    又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。

    (类间解耦,低耦合)意思就是降低各个对象之间的耦合,提高系统的可维护性;在模块之间只通过接口来通信,而不理会模块的内部工作原理,可以使各个模块的耦合成都降到最低,促进软件的复用

    迪米特法则还有几种定义形式,包括不要和“陌生人”说话只与你的直接朋友通信等,谁是朋友呢:

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

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

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

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

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

          任何一个对象,如果满足上面的条件之一,就是当前对象的“朋友”,否则就是“陌生人”。在应用迪米特法则时,一个对象只能与直接朋友发生交互,不要与“陌生人”发生直接交互,这样做可以降低系统的耦合度,一个对象的改变不会给太多其他对象带来影响。

    迪米特法则要求我们在设计系统时,应该尽量减少对象之间的交互,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。

          在将迪米特法则运用到系统设计中时,要注意下面的几点:在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;

          在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类;在对其他类的引用上,一个对象对其他对象的引用应当降到最低。

  • 相关阅读:
    QuantLib 金融计算——基本组件之 Date 类
    挑选合适的机器学习资料
    【翻译】理解 LSTM 及其图示
    《信任的速度》读后感
    Git分支使用心得
    c# 多线程 创建对象实例
    c# 设计模式之单例模式
    C# 设计模式之空对象模式
    c# 静态构造函数与构造函数的调用先后
    C# 中关于接口实现、显示实现接口以及继承
  • 原文地址:https://www.cnblogs.com/hankuikui/p/7095509.html
Copyright © 2011-2022 走看看