Open-Close原则
是一个愿景性质的原则,如果系统能够达到Open-Close原则描述的情形就比较理想了,对扩展开放、对修改关闭,即,不修改原有代码即可完成对系统的扩展。
实现Open-Closed原则,抽象化是关键。
抽象层,因为抽象所以稳定。不变应万变,不用修改,满足Open-Closed原则的Closed一头。
抽象层的具体实现层可以满足扩展要求,满足Open-Closed原则的Open一头。
Open-Closed原则还可表述为“对可变性的封装”原则。“找到一个系统的可变因素,将它封装起来。”
一个可变性因素,不应该被散落在各个角落,而应该被封装到一个对象中。
一种可变性因素,不应该与另一种可变性因素混和在一起,而应各自独立开。
但,单从原则本身来说,它并没有告诉我们如何才能够让系统满足这个原则。
里氏代换原则
指导我们如何去构建一个extends(继承、派生)结构。
子类与父类的关系必须是is-A,即,子类必须在任何场合都敢于大声宣称自己起码(至少)是一个父类。比如,假设某类结构,“男人”、“女人”从“人”派生出来,看起来就是满足里氏代换原则的,因为无论“男人”还是“女人”,在任何场合都是“人”。这个原则大多数情况下,可以用现实世界中的概念来思考,但软件世界与显示世界毕竟有区别,比如,书中的例子,“正方形是不是矩形”问题。
此外,很多问题需要利用OO核心思想来灵活考虑,还是书中的例子(我只说大概意思,可能与书中描述存在差异),一个类结构,“职工、普通职员、项目经理、科长、部长……”,从“员工”类派生出来,从一般概念来看还不错,职工和部长都是员工嘛,但这里隐含问题,现实世界中,普通职员可能变成项目经理,但软件世界中,普通职员和项目经理被规划成两个类了,于是一个普通职员instance是很难变成项目经理instance的,这说明我们把显示世界映射为软件世界时,出现了问题。更加合理的做法是,把这些职务(角色)抽象出来,比如叫做“职务”类(interface/abstract class),所有职务从其派生,员工类、职务类是关联关系,任何一个员工实例都一个职务实例作为它的属性,这样就对了,员工的职务是可以变化的。实现这个重构的依据,是OO中的封装变化思想,以及从中演化出来的依赖倒换原则、合成/聚合复用原则。
但凡涉及到extends结构的设计模式都符合着里氏代换原则:
策略模式:一组算法,把他们封装成对象,使之可以互换(满足同一接口,即都is-A这个接口)。
合成模式:Leaf和Composite都is-A Component,于是才可能方便地层层嵌套。
代理模式:Proxy与RealSubject都is-A父类Subject,于是可以插入代理,完成附加功能。
……
依赖倒换原则
很具体地指导我们对抽象类(接口)、实现类的使用。
依赖于抽象的实体(interface/abstract class),才能够更具有可插入性(但凡实现既有接口的实现类实例都可以在依赖此接口的地方以此接口实例的角色插入进来),更容易满足Open-Close原则(抽象的层次不变化、实现的层次由于使用不同的类来封装不同的变化,于是可以在增加新类作为扩展的同时不需要修改已有实现类)。
接口隔离原则
这个原则比较孤立,也是从OO封装变化思想演化出来的,要将变化封装到最“贴身”。比如,A/B接口可能在大多数情况下都由同一个实现类提供,但某些情况下,B接口都有些实现类是没有意义的,这时候就需要把A/B分开作为两个接口,某些类实现全部A/B接口、某些类仅实现A接口。A/B单独变化,于是把A/B单独封装,接口隔离。
合成/聚合复用原则
与里氏代换原则关系较为紧密,里氏代换原则告诉我们什么情况下使用extends,在不满足里氏代换原则时,还想达到重用的目的,就引出合成/聚合复用原则。上文中,员工与职务的例子,来说明这个事儿就比较合适。
从复用角度来说:“合成/聚合复用”比“继承”复用灵活。前者是动态复用(因而具有可插入性)、后者是静态复用(编译时就固定了复用关系),而且后者的复用有“不支持多重继承”的限制。
迪米特法则
用于解开类之间的不必要的耦合。“不要与陌生人说话”。说起来容易,实际操作的时候很可能出现些无所适从的问题,而解开类之间的耦合是比较重要的,目前我们设计类的时候,增加属性、增加对其他类的调用都比较随意,不太好。
迪米特法则要求:一个对象应当对其他对象有尽可能少的了解。几种其他的表述:只与你直接的朋友通信、不要跟“陌生人”说话(冯远征?)
每个软件单位对其他单位都具有最少的知识,而且局限于那些与本单位密切相关的软件单位。
狭义迪米特法则-规定了谁是Friends、谁是Stranger。Friends圈子包括:
当前对象自身(this)、Instance field(如果field是Map、List等容器类型,则容器内的对象也是朋友)、当前对象创建的对象(调用其构造方法)、当前对象方法的参数对象。
只跟Friends说话,跟Stranger说的话由Friends转述。
狭义迪米特法则的弊端:传递间接调用的小方法太多!解决办法:遵循依赖倒换原则做些折衷处理,让对象依赖于Stranger的抽象层。虽然没有完全断开耦合,至少降低了耦合。
小结
Open-Close原则是比较总体的要求、是愿景。
实现Open-Close原则的关键,是抽象。
依赖倒换原则就是强调抽象的。
有了抽象层,就要有实现层,实现层无疑要从抽象层extends/implements,实现层/抽象层的关系,要依从里氏代换原则。
很多情况不满足里氏代换原则,又要实现复用,于是引出,合成/聚合复用原则。
另外外两个原则是说类之间(接口)关系的。
接口隔离原则,要求类之间的接口更加狭窄,更加确切、更加合身地封装变化。
迪米特法则,要求类之间的接口应该发生在哪些类之间,不应该发生在哪些类之间。帮助我们解开类之间的耦合。
参考文献:
阎宏《Java与模式》
Meilir Page-Jones《UML面向对象设计基础》
[size=medium][/size]
分享到:
相关推荐
面向对象设计原则是软件开发中至关重要的一环,它关乎到代码的可维护性、扩展性和复用性。本文将深入探讨这些原则,并结合实例来解释它们的重要性。 首先,我们需要理解面向对象不仅仅是编程语言中的概念,如封装、...
面向对象设计原则是Java开发中不可或缺的基础,它们指导着开发者创建可维护、可扩展和可复用的软件系统。本文将深入探讨其中的两个核心原则:“开-闭”原则(Open-Closed Principle, OCP)和里氏代换原则(Liskov ...
面向对象设计原则是软件开发中的一种核心思想,它为创建可维护、可扩展且易于理解的代码提供了指导方针。在本文中,我们将深入探讨这些原则,帮助你更好地理解和应用它们。 1. **单一职责原则(Single ...
### 面向对象设计原则详解 面向对象设计原则是一系列指导软件开发人员构建高质量、易于维护和扩展的软件系统的准则。这些原则旨在帮助开发者创建更健壮、更灵活的系统,减少代码间的耦合度,并提高代码的重用性和...
面向对象设计原则与设计模式是软件工程领域的重要组成部分,它们为构建高质量、可维护和可扩展的软件系统提供了指导方针。下面将详细阐述面向对象设计原则及其如何促进软件的复用,以及设计模式的概念。 ### 面向...
对面向对象设计原则的总结,设计模式:“开-闭”原则,里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则
02 第2章 面向对象设计原则02 第2章 面向对象设计原则02 第2章 面向对象设计原则
[No Starch Press] JavaScript 面向对象设计原则 (英文版) [No Starch Press] The Principles of Object-Oriented JavaScript (E-Book) ☆ 图书概要:☆ If you've used a more traditional object-oriented ...
面向对象设计原则总结 面向对象设计原则是软件设计中最重要的原则之一,它们是软件设计的基础和核心。面向对象设计原则的应用可以提高软件的开发效率、质量和可维护性。下面是七大面向对象设计原则的总结: 一、开...
面向对象设计原则是软件开发中的核心概念,尤其在Java、C++等面向对象编程语言中至关重要。这些原则为创建可维护、可扩展和可重用的代码提供了指导框架。这篇文章将深入探讨面向对象设计原则,并结合设计模式进行...