一.常见的面向对象设计原则
单一职责原则(single responsibility principle)
所谓单一职责原则,指的是:一个类应该只有一个引起它变化的原因.这里变化的原因就是所说的"职责",如果一个类有多个引起它变化的原因,那就意味着这个类有多个职责,也就是说,把多个职责耦合在一起了.
这会造成职责的相互影响,可能一个职责的改变,影响了另一个职责的实现,甚至是引起其他职责随之变化,那么这种设计是很脆弱的.
这个原则看起来是很简单和好理解的,但是实际上很难完全做到的,难点在于如何区分"职责".在实际开发中,这个原则也是最容易违反的.
开放-关闭原则(open-close principle)
所谓开闭原则,指的是:一个类应该对拓展开放,对修改关闭.开闭原则是设计中一个非常重要的原则.
开闭原则的要求是,类的行为是可扩展的,而且是在不修改已有的代码情况下进行扩展,也不必改动已有的源代码或二进制代码.看起来有点矛盾,怎么样才能实现呢?
开闭原则的关键在于合理的抽象,分离出变化与不变化的部分,为变化的部分预留可扩展的方式.比如钩子方法或者动态组合对象.
这个原则看起来也很简单,实际上,一个系统要完全做到开闭原则,几乎是不可能的,也没必要.适度抽象可以提高灵活性,使其可扩展,可维护.但是过度抽象,会大大增加系统的复杂程度,应该在需要改变的地方应用开闭原则就可以了.
里氏替换原则(likov substitution principle)
所谓里氏替换原则,指的是:子类型能够替换掉他们的父类型.很明显这是一种多态的应用,它可以避免在多态的应用中,出现一些隐蔽的错误.
通俗的来说,子类可以扩展父类的功能,但是不能修改父类原有的功能.换句话说,子类在继承父类的时候,除了添加新的方法完成新增功能外,尽量不要重写父类的方法.
从另外一个角度来说,里氏替换原则是实现开闭的主要原则之一.开闭原则要求对扩展开放,扩展的一个实现手段就是继承.而里氏替换原则保证子类型能够替换父类,只有能正确替换,才能实现扩展,否则扩展了也会出现错误.
依赖倒置原则(dependency inversion principle)
所谓依赖倒置原则,指的是:要依赖于抽象,而不要依赖于具体的类.要做到依赖倒置原则,典型的要做到:
- 高层模块不应该依赖底层模块,二者都应该依赖其抽象.
- 抽象不应该依赖于具体实现,具体实现应该依赖于抽象.
很多人觉得,层次化调用的时候,应该是高层调用"底层所拥有的接口",这是一种典型的误解.事实上,一般高层模块包含了对业务功能的处理和业务策略的选择,应该被重用,是高层模块影响底层的具体实现.
因此,这个底层的接口应该是由高层提出的,然后由底层来实现的.也就是说,底层接口的所有权是在高层模块,因此是一种所有权的倒置.
倒置接口所有权,这就是著名的好莱坞原则:不要找我们,我们联系你.
接口隔离原则(interface isolation principle)
所谓接口隔离原则,指的是:不应该强迫客户依赖他们不需要的方法.一个类对另一个类的依赖应该建立在最小接口.
这个原则用来处理那些比较"庞大"的接口.这些接口通常会有很多操作声明,涉及到很多的职责.客户在使用这样的接口时,通常会有很多它不需要的方法,这些不需要的方法,对于客户来说,就是一种接口污染.
因此,这样的接口应该被分离,应该按照客户的需求,分离成针对不同客户的接口.这样的接口中,只需要客户需要的操作声明,这样的接口,即方便客户的使用,也可以避免因误用接口而导致的错误.
最少知道原则(least knowledge principle)
所谓最少知道原则,指的是:只和你的朋友谈话.如果两个软件实体无需直接通讯,那么不应当发生直接的相互调用,而是通过第三方转发该调用.
这个原则指导我们,在设计系统的时候,应该尽量减少对象之间的交互,对象只和自己的朋友谈话,从而松散类之间的耦合.通过松散耦合来降低类之间的相互依赖,使得系统具有更好的可维护性.
那么哪些对象才能被当做朋友呢,最少知道原则提供了一些指导:
- 当前对象本身.
- 当前对象的实例变量所引用的对象.
- 当前对象所创建的对象.
- 通过方法参数传递进来的对象
- 方法内所创建或返回的对象.
总之,最少知道原则要求我们的方法调用必须保持在一定的边界范围内,尽量减少对象的依赖关系.
其他原则
合成复用原则:优先使用聚合或者组合来实现,其次才考虑继承关系.
面向接口编程.
二.UML基础
什么是UML?
UML是一种标准的图形化建模语言.
语言:那就是用来交流的,UML主要是在软件开发的整个生命周期所涉及的人员之间进行交流的语言.
建模:模型是使用某种工具对事物的一种表达,通常会表现事物最重要的方面而简化或忽略其他方面.模型在软件上面的主要作用:可以在一定的抽象层次上,使人们通过对模型的分析和研究,来制定出最终的软件结构和内部的相互关系.
为什么要图形化 :图形化的东西直观,简单,准确.
UML的分类用很多种,这里主要简单介绍类图.
类图
类图的基本结构:
一个类的图形表示为长方形,它主要包含三个部分:类名,属性,操作.
类名,没有特殊要求,只要是合法的名称都可以.
属性,用来描述类的特征,语法格式为: 可见性 名称:类型 [=默认值]
方法,用来描述类能干些什么事.语法格式为: 可见性 方法名(参数列表) [: 返回值类型]
可见性: +表示public; -表示是private; # 表示是protect;没有符号就是默认的可见性.
[] 里面是可选的,对于属性,如果有默认值,语法格式就是: 可见性 属性名:类型=默认值
对于方法,如果有返回值类型,语法格式就是: 可见性 方法名 (参数类表) : 返回值类型.
举个例子:
类之间的关系及其表示
类之间的关系由弱到强分别是:依赖,关联,聚合,组合,继承(泛化),实现.
顺口溜:衣冠(禽兽)剧组纪实(依关聚组继实).
关系名称 | 关系描述 | java中体现形式 |
---|---|---|
依赖(Dependence) | 使用关系,uses-a的关系,一个类依赖另一个类的定义 | 局部变量;方法参数;静态方法的引用 |
关联(Association) | 引用关系,一个类对象和另一个类对象有某种关系 | 成员变量 |
聚合(Aggregation) | 整体与部分的关系,has-a的关系.整体与部分可以相互分离,各自用友生命周期.如学校与老师的关系. | 成员变量 |
组合(Composition) | 整体与部分的关系,contains-a的关系.整体控制了部分的生命周期,部分不能脱离整体.如人和大脑的关系 | 成员变量,组合关系中的成员变量一般会在构造方法中赋值 |
泛化(Generalization) | 特殊与一般,父类与子类的关系,is-a的关系. | 关键字extend |
实现(Implementation) | 接口与实现类的关系 | 关键字implements |
详情请参考:类图的关系及其表示