【设计模式】面向对象原则

来源:互联网 发布:linux 开启snmp 编辑:程序博客网 时间:2024/04/29 12:51

对于面向对象语言设计的软件,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一


面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计模式中,它们是从许多设计方案中总结出的指导性原则

7种常用的面向对象设计原则

单一职责原则(Single Responsibility Principle, SRP)

一个类只负责一个功能领域中的相应职责(换句话说,一个类而言,应该只有一个引起它变化的原因)
单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则

开闭原则(Open-Closed Principle, OCP)

软件实体应对扩展开放,而对修改关闭(即软件实体应尽量在不修改原有代码的情况下进行扩展)
软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类
面向对象编程,可以通过系统定义的抽象类或者接口,再通过具体实现进行扩展
抽象化是开闭原则的关键
注意:如果一个系统只是针对xml或者properties文件进行修改,无须进行编译,原则上,认为是一个符合开闭原则的系统

里氏代换原则(Liskov Substitution Principle, LSP)

所有引用基类对象的地方能够透明地使用其子类的对象
在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象
里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象
注意
子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法
②尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现(里氏代换原则是开闭原则的具体实现手段之一)
③ Java语言中,在编译阶段,Java编译器会检查一个程序是否符合里氏代换原则,这是一个与实现无关的、纯语法意义上的检查,但Java编译器的检查是有局限的

依赖倒转原则(Dependence Inversion Principle, DIP)

抽象不应该依赖于细节,细节应该依赖于抽象(换言之,要针对接口编程,而不是针对实现编程)
依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情
在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中
依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象
1.构造注入 2.设值注入(Setter注入)3.接口注入

开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段

开闭原则是目的:一个已有的代码模块,需要很容易增加新的扩展功能(可扩展性),这个已有模块需要是对外开放的;为了使已有模块可以复用(可复用性),已有模块需要是独立的(单一职责,高内聚,不与其他模块耦合在一起),同时为了方便维护(可维护性),已有模块最好不要对原有代码进行修改,也就是需要是对内封闭的;实现了开闭原则的设计,就达到面向对象设计可扩展可复用可维护性的目的,所以说开闭原则是目的!
里氏代换原则是基础:通过针对抽象基类编程(业务逻辑关系的建立),具体运行时代换具体子类对象执行,可以达到开闭原则的目的,该实现过程就是里氏代换原则定义本身,所以说里氏代换原则是理论基础!
依赖倒转原则是手段:牛人们总结了实现里氏代换原则的方法,抽象不依赖于细节,细节应该依赖于抽象的依赖倒转原则。具体就是变量、参数、方法返回、数据类型转换等都要用抽象定义声明,再通过依赖注入(构造注入、设值注入和接口注入)的方式将具体对象注入到有依赖关系的对象中。所以说依赖倒转原则是实现目的手段!

接口隔离原则(Interface Segregation Principle, ISP)

使用多个专门的接口,而不使用单一的总接口
每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干
这里的“接口”往往有两种不同的含义:一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;另外一种是指某种语言具体的“接口”定义,有严格的定义和结构,比如Java语言中的interface
(1) 当把“接口”理解成一个类型所提供的所有方法特征的集合的时候,这就是一种逻辑上的概念,接口的划分将直接带来类型的划分。可以把接口理解成角色,一个接口只能代表一个角色,每个角色都有它特定的一个接口,此时,这个原则可以叫做“角色隔离原则”。
(2)如果把“接口”理解成狭义的特定语言的接口,那么ISP表达的意思是指接口仅仅提供客户端需要的行为
注意: 在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差

合成复用原则(Composite Reuse Principle, CRP)

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

迪米特法则(Law of Demeter, LoD)

一个软件实体应当尽[可能少地与其他实体发生相互作用
如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展会相对容易,这是对软件实体之间通信的限制,迪米特法则要求限制软件实体之间通信的宽度和深度迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。
在迪米特法则中,对于一个对象,其朋友包括以下几类
(1) 当前对象本身(this)
(2) 以参数形式传入到当前对象方法中的对象
(3) 当前对象的成员对象
(4) 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友
(5) 当前对象所创建的对象。
应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度

博客转载

0 0
原创粉丝点击