设计软件的几个原则,这个也是设计模式的精髓所在:
一、 开闭原则(OCP)
开闭原则(Open-Closed Principle):一个软件实体应当对扩展开放,对修改关闭。
客户的需求是不稳定的,通过扩展已有的软件系统而不是通过修改软件系统来满足客户的需求,这样的软件系统就满足开-闭原则,即软件系统要有一定的灵活性和适应性。
已有的模块,特别是抽象层的模块不能修改,保证软件系统的稳定性和延续性。解决问题的关键是抽象化,把它与具体实现分离开来。接口(interface),抽象类的应用对可变性封装:将可变性封装到一个对象里。优点是通过扩展已有软件系统,可以提供新的行为,以满足对软件的新的需求,使变化中的软件有一定的适应性和灵活性。已有软件模块,特别是最重要的抽象层模块不能再修改,这使变化中的软件系统有一定的稳定性和延续性。
实现开闭原则的关键:
抽象化是解决问题的关键,在面向对象的编程语言里,可以给系统定义出一套相对较为固定的抽象设计,此设计允许无穷无尽的行为在实现层被实现。在语言里,可以给出一个或多个抽象类或者接口,规定出所有的具体类必须提供的方法的特征作为系统设计的抽象层。这个抽象层预见了所有的可扩展性,因此,在任何扩展情况下都不会改变。这就使得系统的抽象不需要修改,从而满足了开闭原则的第二条,对修改关闭。
同时,由于从抽象层导出一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展是开放的,这就满足了开闭原则的第一条。
对可变性的封装原则:
这是对开闭原则的另外一种描述,它讲的是找到一个系统的可变因素,将之封装起来。该原则意味着两点:
① 一种可变性不应当散落在代码的很多角落,而应当封装到一个对象里面。继承应当被看做是封装变化的方法,而不应该被认为是一种从一般对象生成特殊对象的方法。
② 一种可变性不应当与另外一种可变性混合在一起。这意味着一般的继承层次不会超过两层。
关键知识点:
☆ 开闭原则的概念,软件实体对扩展开发,对修改关闭;
☆ 实现开闭原则的关键,利用接口或抽象类抽象出系统的抽象层,抽象层不变,利用实现层进行扩展;
☆ 对可变性的封装,将可变的元素封装起来,防止改变扩散到整个应用;
☆ 注意控制封装的粒度,不要将两种可变性封装到一起;
☆ 继承是用来封装可变性的,一般的继承层次不要超过两层;
☆ 策略模式是对开闭原则的很好诠释,其他还有工厂模式、建造模式、桥接模式、门面模式、调停者模式、访问者模式和迭代子模式等;
☆ 对“将条件转移语句改写成多态性”的重构行为应当遵循开闭原则,防止多态性污染;
☆ java下的单方法接口通常用来实现函数指针或者委托的功能;
☆ 任何一棵继承树都要以抽象类为根,具体类不是用来继承的,更不要从工具类继承;
☆ 抽象类要拥有尽可能多的共同代码,同时拥有尽可能少的数据。
☆ 当Coad条件全部满足时,才应当考虑使用继承:派生类是基类的一个特殊种类,而不是其的一个角色,也就是说要区分“Has-a”和“Is-a”;永远不会出现需要将派生类换成另外一个类的派生类的情况;派生类具有扩展基类的责任而不是具有置换或注销基类的责任;只有在分类学角度上有意义时,才可以使用继承。
二、 里氏代换原则(LSP)
里氏代换原则(Liskov Substitution Principle):子类型必须能够替换它们的基类型。反过来的代换不成立。
当两个具体类关系违反里氏代换原则时,一种办法是抽象出一个基类,作为这两个类的父类,一种是应用组合聚合关系建立关系。不要为了使用某些类的方法(功能)而滥用继承。
关键知识点:
☆ 里氏替换原则的概念,基类可以出现的地方,派生类同样可以出现;
☆ 里氏替换原则的反命题不成立;
☆ 对于A、B两个类,B由A派生,如果这种继承违反里氏替换原则,可以采用如下方法进行重构:将A、B的共同行为抽象出来,建立一个抽象类C,A和B都是C的派生类
三、依赖倒置原则(DIP)
依赖倒置原则(Dependence Inversion Principle):具体要依赖于抽象,抽象不要依赖于具体。
简单的说,依赖倒置原则要求客户端依赖于抽象耦合。原则表述:抽象不应当依赖于细节;细节应当依赖于抽象;要针对接口编程,不针对实现编程。传递参数,或者在组合聚合关系中,尽量引用层次高的类。主要是在构造对象时可以动态的创建各种具体对象,当然如果一些具体类比较稳定,就不必再弄一个抽象类做它的父类,这样有画蛇添足的感觉。
☆ 三种耦合关系
① 零耦合关系,如果两个类没有耦合关系,就称之为零耦合;
② 具体耦合,具体耦合发生在两个具体的类之间,经由一个类对另外一个具体类的直接引用造成的。
③ 抽象耦合关系,抽象耦合关系发生在一个具体类和一个抽象类之间,使用两个必须发生关系的类之间存在有最大的灵活性。
☆ 依赖倒转原则的另外一种表述是:
要针对接口编程,不要针对实现编程(Program to an interface, not an implementation)[GOF95]。同样,在处理类之间的耦合关系时,尽量使用抽象耦合的形式。
☆ 里氏替换原则是依赖倒转原则的基础。
☆ 工厂模式、模板模式、迭代子模式都是对依赖倒转原则的体现。
java对抽象类型的支持
☆ 在设计中,常用的抽象方式为:先抽象出逻辑上固定的东西,定义出接口,再定义一个抽象类实现该接口,作为该接口默认实现的抽象类应该实现大部分公共的代码,具体的类通常由该抽象类派生。
四、接口隔离原则(ISP)
接口隔离原则(Interface Segregation Principle):使用多个专门的接口比使用单一的总接口总要好。
换而言之,从一个客户类的角度来讲:一个类对另外一个类的依赖性应当是建立在最小接口上的。过于臃肿的接口是对接口的污染。不应该强迫客户依赖于它们不用的方法。定制服务的例子,每一个接口应该是一种角色,不多不少,不干不该干的事,该干的事都要干。
☆ 接口隔离原则讲的是为同一个角色提供宽、窄不同的接口,以应对不同客户端的需求,下例以set为例讲解:
TreeSet是一种使用树状数据结构的可排序的Set容器,它既实现了Set接口(通过继承AbstractSet),又实现了SortedSet接口。这里并没有提供一个总的既有排序功能又有Set功能的总接口,而是针对不同的需求,将两种角色分别定义成两种接口,这样的设计,是符合接口隔离原则。
☆ 接口污染
将不同角色的接口合并为一个臃肿的接口就是对接口的污染。这种做法同时违反了可变性封装原则,它将不同的可变性封装到了同一个软件实体中。
☆ 对接口隔离原则的具体应用可以参考备忘录模式和迭代子模式。
五、合成/聚合复用原则(CARP)
合成/聚合复用原则(Composite/Aggregate Reuse Principle或CARP):就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新对象通过向这些对象的委派达到复用已有功能的目的。
简而言之,要尽量使用合成/聚合,尽量不要使用继承。区分Has a和Is a的问题。
合成:一荣俱荣,一损俱损,整体和部分的生命周期是一样的。是比聚合关系强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分对象的生命周期,合成关系是不能共享的。代表整体的对象需要负责保持部分对象和存活,在一些情况下将负责代表部分的对象湮灭掉。代表整体的对象可以将代表部分的对象传递给另一个对象,由后者负责此对象的生命周期。换言之,代表部分的对象在每一个时刻只能与一个对象发生合成关系,由后者排他地负责生命周期。
聚合:部分可以是整体的一部分,也可以脱离整体而存在。例如,汽车类与引擎类、轮胎类,以及其它的零件类之间的关系便整体和个体的关系。聚合关系也是通过实例变量实现的。但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在不平等层次上的,一个代表整体,另一个代表部分。
六、迪米特法则(LoD)
迪米特法则(Law of Demeter或简写LoD)又叫最少知识原则(Least Knowledge Principle或简写为LKP):一个对象应当对其它对象有尽可能少的了解。不要和陌生人说话。
ξ 1 迪米特法则的各种表述
① 只与你直接的朋友们通信;
② 不要跟“陌生人”说话;
③ 每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
ξ 2 狭义的迪米特法则
☆ 如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另外一个类的某一个方法,可以通过第三者转发这个调用。
参考下例,Someone、Friend和Stranger三个类。

Someone类有一个方法接受一个Friend类型的变量:
所以Someone和Friend是朋友类(直接通讯的类)。
同理,Friend类持有一个Stranger类的私有对象,他们是朋友类:
在这里,Someone类和Stranger类不是朋友类,但Someone类却通过Friend类知道了Stranger类的存在,这显然违反迪米特法则。
现在,我们对Someone和Friend类进行重构。首先在Friend类里添加一个方法,封装对Stranger类的操作:
然后,我们重构Someone的operation1方法,让其调用新提供的forward方法:
现在Someone对Stranger的依赖完全通过Friend隔离,这样的结构已经符合狭义迪米特法则了。
仔细观察上述结构,会发现狭义迪米特法则一个明显的缺点:会在系统里造出大量的小方法,散落在系统的各个角落。这些方法仅仅是传递间接的调用,因此与系统的商务逻辑无关,当设计师试图从一张类图看出总体的框架时,这些小的方法会造成迷惑和困扰。遵循迪米特法则会使一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有直接关联。但是,这也会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。
结合依赖倒转原则,我们对代码进行如下重构来解决这个问题,首先添加一个抽象的Stranger类,使Someone依赖于抽象的“Stranger”角色,而不是具体实现:
然后,让Stranger从该类继承:
随后,我们重构Someone使其依赖抽象的Stranger角色:
最后,我们重构Friend的provide方法,使其返回抽象角色:
现在,AbstractStranger成为Someone的朋友类,而Friend类可以随时替换掉AbstractStranger的实现类,Someone不再需要了解Stranger的内部实现细节。下图是重构后的UML类图:

广义迪米特法则
☆ 在将迪米特法则运用到系统的设计中时,应注意的几点:
① 在类的划分上,应该创建有弱耦合的类;
② 在类的结构设计上,每一个类都应当尽量降低成员的访问权限;
③ 在类的设计上,只要有可能,一个类应当设计成不变类;
④ 在对其他类的引用上,一个对象对其它对象的引用应当降到最低;
⑤ 尽量降低类的访问权限;
⑥ 谨慎使用序列化功能;
⑦ 不要暴露类成员,而应该提供相应的访问器(属性)。
七、抽象类原则
抽象类不会有实例,一般作为父类为子类继承,一般包含这个系的共同属性和方法。
注意:好的继承关系中,只有叶节点是具体类,其他节点应该都是抽象类,也就是说具体类是不被继承的。将尽可能多的共同代码放到抽象类中。
分享到:
相关推荐
软件设计的七大原则是软件设计的精髓所在,这七大原则分别是开闭原则、里氏代换原则、依赖倒置原则、接口隔离原则、合成/聚合复用原则、迪米特法则和抽象类原则。 一、 开闭原则(OCP) 开闭原则是指一个软件实体...
软件设计的七大原则(OOD) software设计的七大原则是指在软件设计中遵守的一些基本原则,以提高软件的可复用性、灵活性、可扩展性和可维护性。其中包括SRP(单一职责原则)、OCP(开闭原则)、LSP(里氏替换原则)...
软件设计的七大原则 软件设计的七大原则是软件设计的基本原则,旨在指导软件模块的开发和扩展。这些原则包括开闭原则、里氏代换原则、依赖倒置原则、接口隔离原则、合成/聚合复用原则、迪米特法则和抽象类原则。...
软件设计原则-面向对象设计七大原则.zip 面向对象和C语言完全不是一种思考问题的方式,面向对象是种哲学思想,只有明白了其核心思想,才能以不变应万变 只有吃透面向对象的七大设计原则,比如:依赖倒置原则,迪米特法则等...
软件体系结构七大设计原则是构建高质量软件系统的基础,它们分别是:单一职责原则、开闭原则、里氏代换原则、依赖倒转原则、接口隔离原则、迪米特法则和合成聚合原则。这些原则旨在提高软件的可维护性、可扩展性和可...
【软件设计原则详解】 在软件开发领域,遵循一系列设计原则对于构建高质量、可维护和易于扩展的系统至关重要。以下是一些关键的软件设计原则,它们不仅适用于编程,还能应用于更广泛的生产活动和生活。 1. **Don’...
为了达到这样的设计目标,业界总结了一系列设计原则,这些原则被统称为“软件设计6原则”,它们分别是:单一责任原则(Single Responsibility Principle,简称SRP)、开放封闭原则(Open/Closed Principle,简称OCP...
软件设计原则是指导开发者构建高质量、可维护和可扩展软件的核心概念。这些原则不仅提高了代码的灵活性,还降低了长期维护的成本。以下是一些主要的软件设计原则及其详细解释: 1. **面向对象的设计原则**: - 可...
总结来说,软件设计原则在嵌入式领域的应用,要求开发者在设计和实现时考虑系统的可维护性、可扩展性和复用性。通过合理应用开闭原则、单一职责原则、模块化、依赖倒置原则、设计模式以及代码结构的继承和抽象,可以...
### 设计模式六大原则详解 #### 一、开闭原则(Open-Closed Principle) **含义:** ...这些原则不仅适用于特定的技术栈或编程语言,而且是一种通用的软件设计思想,对于构建高质量的软件系统至关重要。
软件开发设计原则 软件开发设计原则是指在软件开发过程中所遵循的一些基本原则,这些原则可以帮助开发者编写出更加灵活、可维护、可扩展的代码。这些原则包括单一职责原则、开放封闭原则、里氏替换原则、最少知识...
#### 第三章:软件设计原则 **设计原则的重要性:** 良好的设计原则对于构建高质量、可维护的软件至关重要。它们帮助开发者: - **优化软件架构:**确保系统结构合理,易于理解和扩展。 - **提高代码质量:**促进...
软件设计的原则是构建高质量、可维护软件的关键。本文将深入探讨S.O.L.I.D.设计原则,这一组原则由Robert C. Martin(也被称为Bob大叔)在其著作《Agile Principles, Patterns, and Practices in C#》中提出。此外,...
8. 方案生命周期长设计原则:软件设计应考虑到整个生命周期,能够满足业务需求和用户需求。 在软件设计过程中,需要遵循这些基本原则,以确保软件的质量、效率和可维护性。而且,软件设计也需要考虑到业务发展的...
软件设计的七大原则之思维导图
依赖倒置原则(Dependence Inversion Principle, DIP)也是软件设计中非常重要的一个原则。它强调高层模块不应依赖于低层模块,二者都应依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。简单来说,依赖倒置...
软件设计的常用原则ppt 软件设计的常用原则ppt
### 程序设计的七大原则详解 #### 一、开-闭原则 (Open-Closed Principle, OCP) 开-闭原则是面向对象设计中最基本的原则之一,它强调软件实体应该对扩展开放,对修改关闭。这意味着在设计一个模块时,应该能够让它...