Java设计模式面试题 01 – 六大原则
1. 单一职责原则
Single Responsibility Principle SRP原则
分清职责,接口一定要做到单一职责,方法也要做到,类尽量做到
定义:单一职责原则指的是应该有且仅有一个原因引起类的变更。
2. 里氏替换原则
Liskov Substitution Principle LSP原则
定义:所有引用基类的地方必须能透明地使用其子类的对象,通俗的来讲就是父类能出现的地方子类就可以出现,但是反过来就不行了。子类可以扩展父类的功能,但不能改变父类原有的功能。
里氏替换原则为良好的继承定义了一个规范;
在类中调用其他类时务必要使用父类或者接口,如果不能使用父类或者接口,则说明类的设计已经违背了LSP原则;
我们在做系统设计时,经常会定义一个接口或者抽象类,然后编码实现,调用类则直接传入接口或者抽象类,不关心具体实现;
如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承;
在项目中采用里氏替换原则时,尽量避免子类的个性,一旦子类有个性这个子类和父类的关系就很难调和了。
定义包含四层意思:
1) 子类可以实现父的抽象方法,但不能覆写父类的非抽象方法。 父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。
2) 子类中可以增加自己特有的方法。
3) 覆写 或实现父类的方法时,输入参数可以被放大。(覆写指的覆写一个正常方法并重写,是实现指的是实现接口或者抽象方法)
4) 覆写或实现父类的方法时输出结果可以被缩小(若放大,还能用子类替换父类吗?)
3. 依赖倒置原则
Dependence Inversion Principle DIP原则
定义:
1)高层模块不应该依赖低层模块
2)抽象不应该依赖细节
3)细节依赖抽象
在Java中的表现为:面向接口编程 OOP
1)模块间的依赖通过抽象发生,实现类间不发生直接的依赖关系,其依赖关系通过接口或者抽象类产生;
2)接口或抽象类不依赖于实现类
3)实现类依赖于接口或者抽象类
依赖倒置原则可以减少类之间的耦合性,提高系统的稳定性;降低并行开发引起的风险。
要并行开发就要解决模块间的依赖关系,依赖倒置原则正好解决这个问题。
在Java中,只要定义变量就必然要有类型,一个变量可以有两种类型,表面类型和实际类型,UserDao是表面类型,UserDaoImpl是实际类型。
依赖的三种写法:依赖是可以传递的,只要做到抽象依赖,即使是多层的依赖也没关系。
1)构造函数传递依赖对象
2)Setter方法传递依赖对象
3)接口方法中传入依赖对象
最佳实践:
1)每个类尽量都有接口或者抽象类
2)变量的表面类型尽量是接口或者抽象类
3)不从具体类派生类
4)尽量不覆写基类的方法,只实现;
倒置的概念就是所谓的抽象依赖。
4. 接口隔离原则
Interface Segregation Principle ISP原则
把一个臃肿的接口变更为两个独立的接口所依赖的原则就是接口隔离原则;
定义:
客户端不应该依赖它不需要的接口
类间的依赖关系应该建立在最小的接口上;
根据接口隔离原则拆分接口时,首先必须满足单一职责原则;
接口要高内聚,高内聚就是提高接口、类、模块的处理能力,减少对外交互。
定制服务,为不同的用户定制不同的服务
接口设计要适度,各方都要照顾。
接口和类尽量使用院子接口或原子类来组装,但是这个原子接口或原子类该怎么组装,是一个难题。在实践中可根据以下标准来衡量:
1)一个接口只服务于一个字模块或业务逻辑
2)通过业务逻辑压缩接口中的public方法
3)已被污染的接口尽量去修改,若变更风险大,可用适配器模式进行转化处理
4)了解业务背景,避免生搬硬套模式。
开发中只能根据,经验和常识来判断接口粒度的大小。
5. 迪米特法则
Law of Demter LoD
也称为最少知识原则:Least Knowledge Principle LKP
描述的是,一个对象应该对其他对象有最少的了解,一个类只需要知道自己需要耦合或者调用类的public方法即可。
尽量保证风险的不扩散,修改的地方越少,代码就越好。
一个类公开的public方法越多,修改时涉及的面也越大,变更的风险也越大。
只和朋友交流:
朋友类的定义:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类,迪米特法则告诉我们,一个类 只和他的朋友类做交流,老师和体育委员交流、体育委员和学生交流。
在实际中如果遇到,一个方法放在本类中也可以,放在其他类中也合适,那么你可以坚持这样一个原则:如果一个方法放在本类中,既不增加类间关系,也 对本类不产生负面影响,那就放置在本类中。
迪米特法则的核心观念就是类间的解耦,弱耦合。但是也要衡量,既要让结构清晰,又要高内聚低耦合。
我们在使用原则时,要反复衡量。
6. 开闭原则
Java世界里最基础的设计原则
定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
根据3W原则介绍
什么是开闭原则?
软件实体包括:项目或者软件产品中按照一定的逻辑规则划分的模块。
抽象和类
方法
一个软件产品在开发周期内,肯定会有变化,我们的设计应该尽量适应这些变化,开闭原则则告诉我们尽量通过扩展软件实体的行为来实现变化,而不是修改已有的代码来完成变化。
为什么使用开闭原则? — 重要性
前五章介绍的原则都是开闭原则的具体形态,开闭原则是精神领袖。
对测试的影响
可提高复用性
可提高可维护性
面向对象开发的要求
如何使用开闭原则?
开闭原则是非常虚的一个原则;
抽象约束、元数据控制模块行为、制定项目章程、封装变化;
封装变化有两层含义,第一将相同的变化封装到一个接口或抽象类中;第二,将不同的变化封装到不同的接口或抽象类中。23种设计模式都是从各个不同的角度对变化进行封装的;
总结:
Single Responsibility Principle
Open Closed Principle
Liskov Substitution Principle
Law of Demeter
Interface Segregation Principle
Dependence Inversion Principle
这六个字母联合起来 Solid 稳定的;
笔记来源—设计模式之禅(秦小波著)