第二部分 面向对象的设计原则
如何同时提高一个软件系统的可维护性(Maintainability)和可复用性(Reuseability)是面向对象的设计要解决的核心问题。
一个好的系统设计应该有如下的性质:可扩展性(Extensibility)、灵活性(Flexibility)、可插入性(Pluggability)。
系统的可扩展性是由“开-闭”原则、里氏代换原则、依赖倒转原则和组合/聚合复用原则所保证的。
恰当地提高系统的可复用性,可以提高系统的灵活性。在一个设计得当的系统中,每一个模块都相对于其他模块独立存在,并只保持与其他模块的尽可能少的通信。这样一来,在其中某一个模块发生代码修改的时候,这个修改的压力不会传递到其他的模块。
系统的灵活性是由“开-闭”原则、迪米特法则、接口隔离原则所保证的。
恰当地提高系统的可复用性,可以提高系统的可插入性。在一个符合“开-闭”原则的系统中,抽象层封装了与商业逻辑有关的重要行为,这些行为的具体实现由实现层给出。当一个实现类不再满足需要,需要以另一个实现类取代的时候,系统的设计可以保证旧的类可以被“拔出(Unplug)”,新的类可以被“插入(Plug)”。
系统的可插入性是由“开-闭”原则、里氏代换原则、依赖倒转原则和组合/聚合复用原则所保证的。
1、“开-闭原则”(Open-Closed Principle,缩写为OCP)
“开-闭”原则:一个软件实体应当对扩展开放,对修改关闭。
如何实现?
(1)抽象化是关键
在Java 语言里,可以给出一个或多个抽象 Java 类或Java 接口,规定出所有的具体类必须提供的方法的特征作为系统设计的抽象层。这个抽象层预见了所有的可能扩展,因此,在任何扩展情况下都不会改变。这就使得系统的抽象层不需要修改,从而满足了“开-闭”原则的第二条:对修改关闭。
同时,由于从抽象层导出一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展时开发的,这就满足了“开-闭”原则的第一条:对扩展开放。
(2)对可变性的封装原则
找到一个系统的可变因素,将它封装起来。一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。一种可变性不应当与另一种可变性呼喝在一起。所有的类图的继承接口一般不会超过两层,不然就意味着将两种不同的可变性混合在了一起。
相关的设计模式:策略模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造模式、桥梁模式、门面模式、调停者模式、访问者模式迭代子模式。
当读者学习设计模式的时候,要学会问一个问题:这个设计模式可以对什么样的变换开放,以及它做到这一点所付出的代价是什么。通过这样的思考,可以更加透彻地了解这种模式对“开-闭”原则的支持程度,以及这种设计模式本身。
当代码包含大段大段的代码转移语句块往往意味着某种可变性。可以将这种可变性用多态代替,就意味着将这种可变性封装起来。但是如果一个条件转移语句没有涉及重要的商务逻辑,或者不糊随着时间的变化而变化,也不意味着任何的可扩展性,那么它就没有涉及任何有意义的可变性,这时候运用多态性就是毫无意义的。
附加专题内容:
Java 接口的常见的用法:单方法接口、标识接口、常量接口。
在设计中,只要有可能,不要从具体类继承。从继承的等级结构里面,树叶节点均应当是具体类,而树枝节点均应当是抽象类(或接口)。这样的设计是所有的Java 设计师都应当努力做到的。
继承使用的条件,当以下的条件全部满足时:
(1)子类是超类的一个特殊种类,而不是超类的一个角色,也就是要区分“Has-A”与“Is-A”两种关系的不同。Has-A关系应当使用聚合关系描述,而只有Is-A关系才符合继承关系。
(2)永远不会出现需要将子类换成另一个类的子类的情况。如果设计师不是很肯定一个类会不会在将来变成另一个类的子类的话,就不应当将这个类设计成当前这个超类的子类。
(3)子类具有扩展超类的责任,而不是具有置换掉(Override)或者注销掉(Nullify)超类的责任。如果子类需要大量地置换掉超类的行为,那么这个子类不应当成为这个超类的子类。
(4)只有在分类学角度上有意义时,才可以使用继承,不要从工具类继承。
2、里氏代换原则(Liskov Substitution Principle,缩写为LSP)
里氏代码原则的严格表达是:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。换而言之,一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能察觉出基类对象和子类对象的区别。
里氏代换原则讲的是基类与子类的关系。如果有两个具体类A和B 之间的关系违反了这一原则的设计,根据具体情况可以在下面的两种重构方案中选择一种。
相关的设计模式:策略模式、合成模式、代理模式。
3、依赖倒转原则(Dependence Inversion Principle,缩写为DIP)
依赖倒转原则讲的是:要依赖于抽象,不要依赖于具体。也就是说抽象不应当依赖于细节;细节应当依赖于抽象。另一种表述是,要针对接口编程,不要针对实现编程。
下图是违反依赖倒转原则的设计:
正确的设计应该是:
相关设计模式:工厂方法模式、模板方法模式、迭代子模式。
依赖倒转原则的缺点是因为依赖倒转的缘故,对象的创建很可能要使用对象工厂,以比秒对具体类的直接引用,此原则的使用还会导致大量的类。
4、接口隔离原则(Interface Segreation Principle,缩写为ISP)
接口隔离原则讲的是:使用多个专门的接口比使用单个的总接口要好。换而言之,从一个客户类的角度来讲,一个类对另外一个类的依赖性应当是建立在最小的接口上的。
接口隔离原则的一般常用的有:角色的合理划分、定制服务。
5、合成/聚合复用原则(Composite/Aggregate Reuse Principle,缩写为CARP)
合成/聚合复用原则就是:在一个新的对象里面使用一些已有的对对象,使之成为新对象的一部分,新的对象通过向这些对象的委派达到复用已有功能的目的。另一种表述是:尽量使用合成/聚合,尽量不要使用继承。
合成和聚合的区别:聚合用来表示“拥有”关系或者整体与部分的关系;而合成则用来表示一种强得多的“拥有”关系,在合成关系里,部分和整体的生命周期是一样的。
6、迪米特法则(Law of Demeter,缩写为LoD)
迪米特法则又叫做最少知识原则,就是说,一个对象应当对其他对象有尽可能少的了解。
狭义的迪米特法则:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
下图是一个不满足迪米特法则的系统:
满足地卡特法则的系统应该为:
上图中使用了Friend 类作为中间层,间接调用Strange 类的方法。这样使得调用的具体细节被隐藏在Friend内部,从而使Someone与Strange 之间的直接联系被省略掉了。这样一来,使得系统内部的耦合度降低。
但这样做有个明显的缺点:会在系统里造出大量的小方法,散落在系统的各个角落。这些方法仅仅是传递间接的调用。
广义的迪米特法则:其实,迪米特法则所谈论的,就是对对象之间的信息流量、流向以及信息的影响的控制。
在软件系统中,一个模块设计得好与不好的最主要、最重要的标志,就是该模块在多大的程度上将自己的内部数据和其他与实现有关的细节隐藏起来。一个设计得好的模块可以将它所有的实现细节隐藏起来,彻底地将提供给外界的API和自己的实现分隔开来,而不理会模块内部的工作细节。这一概念就是“信息的隐藏”,或者叫封装。
迪米特法则的主要用意是控制信息的过载。在将迪米特法则运用到系统设计中时,要注意下面的几点:
(1)在类的划分上,应当创建有弱耦合的类。类之间的耦合越弱,就越有利于复用。一个处在弱耦合中的类一旦被修改,不会对有关系的类造成波及。
(2)在类的结构设计上,每一个类都应当尽量降低成员的访问权限。换言之,一个类包装好各自的private 状态。这样一来,想要了解其中的一个类的意义时,不需要了解更多别的类的细节。一个类不应当public 自己的属性,而应当提供取值和赋值方法让外界间接方法自己的属性。
(3)在类的设计上,只要有可能,一个类应当设计成不变类。
(4)在对其他类的引用上,一个对象对其对象的引用应当降低到最低。
相关设计模式:门面模式、调停者模式。
这篇总结是我在一年前从 Java 与模式书上摘录的,自己觉得有用,容易忘记的,有时间便记录总结下。发表在这主要是为了方便以后能更好的回顾,还有几篇也将陆续整理下发表。。by zhxing
相关推荐
### Java设计模式学习笔记 #### 1. 设计模式的七大原则 ##### 1.1 设计模式的目的 设计模式是一种解决特定问题的通用解决方案,它可以帮助开发人员编写出更高质量、更容易维护和扩展的代码。设计模式的目标在于...
这份"根据《JAVA与设计模式》整理的笔记及示例代码"涵盖了Java语言和设计模式的核心概念,旨在帮助开发者理解和应用这些模式。 一、设计模式的基本概念 设计模式是对在特定情境下软件设计问题的解决方案的一种描述...
通过以上内容,我们可以看到韩顺平老师的Java设计模式笔记涵盖了设计模式的基础概念、常见面试题解析、设计原则等内容,并通过具体案例来阐述设计模式的实际应用价值,旨在帮助学习者深刻理解并掌握设计模式,从而在...
在学习Java设计模式时,掌握其概念、应用、优点和缺点非常重要。设计模式是软件开发中经常使用的一种通用解决方案模板,用于解决特定上下文中的常见问题。它们源于设计模式的研究,通常被认为是软件设计中的最佳实践...
以上只是Java设计模式笔记的冰山一角,实际笔记中还会有更多关于每种模式的详细描述、示例代码和应用场景。通过学习和应用这些模式,开发者可以写出更加优雅、可维护的代码,提升团队协作效率和软件质量。
Java设计模式是软件开发中的一种最佳实践,它们是为了解决特定场景下的设计问题而发展起来的。23种设计模式被广泛应用于提高代码的可重用性、可读性、可维护性和灵活性。韩顺平老师的Java设计模式课程通过生活中的...
本资料包“java设计模式源码和笔记(第一部分)”提供了对Java设计模式的深入理解和实践。其中包含了个人的学习笔记和Eclipse环境下实现的源码,方便读者导入后直接运行,进行实践操作。 1. **单例模式**:确保一个...
Java设计模式是软件开发中的重要概念,它...以上是对“图解Java设计模式笔记总结word版本”中可能包含的知识点的详尽解析,通过深入理解这些设计模式和原则,开发者可以更好地构建高效、稳定和易于维护的Java应用程序。
### Java设计模式整理笔记 #### 一、UML结构图 **1. 类图** - **定义**: 显示出类、接口以及它们之间的静态结构和关系的图。 - **分类**: - **描述类**: 包含五个部分:类名、属性清单、方法清单、性质清单、...
在线阅读地址:设计原则创建型模式作用:将创建与使用代码解耦结构型模式作用:将不同的功能代码解耦桥接模式装饰器模式适配器模式外观模式组合模式享元模式行为型模式(更新中...)作用:将不同的行为代码解耦观察...
读书笔记:软件设计原则与设计模式 Java实现
Java模式是面向对象设计中的一种最佳实践集合,它通过总结并提炼出在软件设计中反复出现的问题和解决方案,为开发者提供了可复用的设计方案。在Java编程中,遵循这些模式可以提高代码的可读性、可维护性和可扩展性。...
设计模式笔记 设计模式是软件开发中常用的解决方案,能够提高代码的灵活性、可维护性和可扩展性。以下是设计模式的七大原则和两种常用的创建型设计模式。 1. "开-闭"原则 "开-闭"原则是设计模式的核心原则,指...
文档中描述的是Java设计模式学习笔记,目前涉及了7种设计模式,但没有具体指明这7种模式是什么,计划后续增加更多的模式。虽然文件内容中存在OCR扫描的识别错误,但不影响我们从整体上把握设计模式的脉络和学习方法...
### 设计模式学习笔记 #### 一、设计模式概述 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。设计...
Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现为Oracle公司)于1995年发布。Java的设计目标是具有高度的可移植性、...同时,这也是一个良好的实践机会,帮助理解面向对象设计和软件工程的基本原则。
- **设计模式**:常见的23种设计模式,如单例、工厂、观察者等,是解决特定问题的模板。 - **算法与数据结构**:基础的排序、查找算法,以及链表、树、图等数据结构。 - **网络编程**:TCP/IP协议栈,套接字编程...
从入门到精通--------java笔记完整版》是一部全面深入学习Java编程语言的教程,由知名IT教育专家韩顺平精心编撰。这部笔记旨在帮助初学者逐步掌握Java的核心概念和技术,同时也适合有一定基础的开发者进行深入学习和...