OOD的设计原则

OCP --Open-Close Principle 开放封闭原则
指系统应该对扩展是开放的,而对于修改是封闭的。简单的说就是,对可变性封装。可扩展性指,模块的行为功能可以被扩展,在应用需求改变或需要满足新的应用需求时,我们可以让模块以不同的方式工作。不可更改指,这些模块的源代码是不可改动的。任何人都不许修改模块的源代码。
在设计代码的时候要将变化的(或者可能变化的)部分提取出来,和那些不会改变代码分离。这样在以后需求变更的时候,我们就可以增加、修改系统功能,但不需要对已有代码做大幅度的改变。
实现OCP,抽象化是关键。因为抽象所以稳定,以不变应万变,不用修改。OCP还可表述为“对可变性的封装”原则。“找到一个系统的可变因素,将它封装起来。” 实现开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和对多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。这是实施开放封闭原则的基本思路,同时这种机制是建立在两个基本的设计原则的基础上,这就是Liskov替换原则和合成/聚合复用原则。
对于违反这一原则的类,必须进行重构来改善,常用于实现的设计模式主要有Template Method模式和Strategy模式。而封装变化,是实现这一原则的重要手段,将经常发生变化的状态封装为一个类。
这个原则理论性更多一点。有人总结了2条经验吧,可以结合代码细细体会。
◆一个可变性因素,不应该被散落在各个角落,而应该被封装到一个对象中。
◆一种可变性因素,不应该与另一种可变性因素混和在一起,而应各自独立开。
LSP--Liskov Substitution Principle里氏代换原则
这个原则主要说明,如何进行继承。先来看看一个比较抽象的概念。如果对于类型S的每一个对象o1,都有一个类型T的对象o2,使对于任意用类型T定义的程序P,将o2替换为o1,P的行为保持不变,则称S为T的一个子类型。这个原则和面向接口编程有点神似。基本的意思就是,子类继承父类的时候,不要扩展父类的方法,只需继承。这样就可以把实现类赋值给抽象类型,其他对象持有抽象类型,调用实现类的方法。子类不扩展父类的方法就是为了,通过父类来操纵子类。
LSP优点:
1、保证系统或子系统有良好的扩展性。只有子类能够完全替换父类,才能保证系统或子系统在运行期内识别子类就可以了,因而使得系统或子系统有了良好的扩展性。
2、实现运行期内绑定,即保证了面向对象多态性的顺利进行。这节省了大量的代码重复或冗余。避免了类似instanceof这样的语句,或者getClass()这样的语句,这些语句是面向对象所忌讳的。
3、有利于实现契约式编程。契约式编程有利于系统的分析和设计,指我们在分析和设计的时候,定义好系统的接口,然后再编码的时候实现这些接口即可。在父类里定义好子类需要实现的功能,而子类只要实现这些功能即可。
使用LSP注意点:
1、此原则和OCP的作用有点类似,其实这些面向对象的基本原则就2条:1:面向接口编程,而不是面向实现;2:用组合而不主张用继承
2、LSP是保证OCP的重要原则
3、这些基本的原则在实现方法上也有个共同层次,就是使用中间接口层,以此来达到类对象的低偶合,也就是抽象偶合!
4、派生类的退化函数:派生类的某些函数退化(变得没有用处),Base的使用者不知道不能调用,会导致替换违规。在派生类中存在退化函数并不总是表示违反了LSP,但是当存在这种情况时,应该引起注意。
5、从派生类抛出异常:如果在派生类的方法中添加了其基类不会抛出的异常。如果基类的使用者不期望这些异常,那么把他们添加到派生类的方法中就可以能会导致不可替换性。
DIP -- Dependence Inversion Principle 依赖倒换原则
先摘录DIP的定义,很定义很抽象
1、高层模块不应该依赖于底层模块,二者都应该依赖于抽象
2、抽象不应该依赖于细节,细节应该依赖于抽象
二、关于高层模块与底层模块
高层模块是系统不经常发生变化的部分,是一个系统区别于其它系统的重要标志,也是直接面向客户的部分,它包含了系统的策略选择与业务模型。
低层模块是系统中经常发生变化的部分,是系统的实现,是用于驱动系统工作的,它不是(直接)面向客户的。
三、违反DIP原则的后果
DIP原则其实强调的是:不要让不经常发生变化的部分去依赖于经常发生变化的部分。因为一旦经常发生变化的那部分发生了变化,那不经常发生变化的那 部分也要随之变化。这是不合理的设计。更坏的情况是,违反DIP的设计会使你的高层模块很难在不同的场合在被重用,因为此时高层模块的工作是依赖于底层模 块的,这种依赖性使高层模块很难独立开来。
四、依赖抽象与接口所有权的倒置
高层模块与低层模块都应该依赖于抽象,为什么这样说?这是因为抽象的东西不同于具体的东西,抽象的东西发生变化的频率要低,让高层模块与底层模块去 依赖于一个比较的稳定的东西比去依赖一个经常发生变化的东西的好处是显而易见的。表现在代码中,就是多使用接口与抽象类,而少使用具体的实现类。(这样说 可能有点不合适,如果一个具体类不经常发生变化,那完全可以让高层模块去依赖于它)。
面向对象的设计中,提倡“面向接口”的编程,在某种程度上,接口与一个抽象类是一样的。面向接口的编程其实就是利用了抽象将高层模块(如一个类的调用者)与具体的被操作者(如一个具体类)隔离开来,从而使具体类在发生变化时不致于对调用者产生影响。
为了使底层模块的修改不影响高层模块,我们在设计时应该采用面向接口的编程方法,让高层与底层都去依赖接口(抽象),但是接口是由谁来声明呢?接口应该是客户(即高层模块)来定义,而底层则去实现这些接口,这样,就象是客户提出了它需要的服务,而底层则去实现这些服务,这样当底层实现逻辑发生改变化 时,高层模块将不受响。但有些时候我们不是这样的,我们在定义接口时可能是由底层去定义并公开接口的,这样做会有问题,因为当底层的接口改变时,高层同样 会受到牵连。这就是“接口所有权”的倒置,即由客户定义接口,而不是由“底层”定义接口
五、DIP的关键
DIP是区别于过程化设计与面向对象设计的重要特性。DIP的关键其实在于找到系统中“变”与“不变”的部分,并利用接口将其隔离,这不是一件容易 的事件。因为在系统设计的初期,我们还难预料到系统中那个部分将来是经常会发生变化的部分,只有当事情发生了,我们才有可能知道。这时,我们应该应用 DIP来对系统做出个性,从使你的系统具有应对变化的弹性。
六、遵循DIP会带来的好处
首先,如果你的系统在设计时遵循了DIP原则,那么你的系统在重用时将会变化的容易。再者,由于遵循了DIP,你的系统在应对需求的变化时就有了一定的弹性(更多需求的变化都表现在底层),同时,由于这种弹性,你的系统将更容易维护。
ISP--Interface Segregation Principle 接口隔离原则
接口隔离原则讲的是,使用多个专门的接口比使用单一的总接口要好。一个类对另外一个类的依赖性应当是建立在最小的接口上的。一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
从一个客户角度讲:一个类对另外一个类的依赖应当是建立在最小接口上的。不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
CARP--Composite/Aggregate Reuse Principle合成/聚合复用原则
与里氏代换原则关系较为紧密,里氏代换原则告诉我们什么情况下使用extends,在不满足里氏代换原则时,还想达到重用的目的,就引出合成/聚合复用原则。从复用角度来说:“合成/聚合复用”比“继承”复用灵活。前者是动态复用(因而具有可插入性)、后者是静态复用(编译时就固定了复用关系),而且后者的复用有“不支持多重继承”的限制。
CARP就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。简而言之,要尽量使用合成/聚合,尽量不要使用继承。
LoD--Law of Demeter迪米特法则
LKP--Least Knowledge Principle最少知识原则
迪米特法则可以简单说成:talk only to your immediate friends。 对于面向OOD来说,又被解释为下面几种方式:
一个软件实体应当尽可能少的与其他实体发生相互作用。每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
迪米特法则不希望类直接建立直接的接触。如果真的有需要建立联系,也希望能通过它的友元类来转达。因此,应用迪米特法则有可能造成的一个后果就是:系统中存在大量的中介类,这些类之所以存在完全是为了传递类之间的相互调用关系——这在一定程度上增加了系统的复杂度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值