如2019年上半年第39题
进行面向对象设计时,就一个类而言,应该仅有一个引起它变化 的原因,这属于()设计原则 。
A、单一职现
B、开放-封闭
C、接口分离
D、里氏替换
答:虽然很简单,但还是那个原则,知道就是知道不知道就是不知道,不能猜。若真答不上来就是仔细审题,从题中找信息。
答案选择:A
其实是有六大原则 的,仅就内容做一个介绍:
单一职责原则
单一职责原则,Single Responsibility Principle,简称SRP。其定义是应该有且仅有一个类引起类的变更,这话的意思就是一个类只担负一个职责。
开闭原则
开闭原则,Open Closed Principle,是Java世界里最基础的设计原则,其定义是:
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭
也就是说,一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码实现变化。这是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。
在我们编码的过程中,需求变化是不断的发生的,当我们需要对代码进行修改时,我们应该尽量做到能不动原来的代码就不动,通过扩展的方式来满足需求。
里氏替换原则
里氏替换原则,英文名Liskov Substitution Principle,它的定义是
如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有对象o1都替换成o2的时候,程序P的行为都没有发生变化,那么类型T2是类型T1的子类型。
看起来有点绕口,它还有一个简单的定义:
所有引用基类的地方必须能够透明地使用其子类的对象。
通俗点说,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何异常。 但是反过来就不行了,因为子类可以扩展父类没有的功能,同时子类还不能改变父类原有的功能。
我们都知道,面向对象的三大特征是封装、继承和多态,这三者缺一不可,但三者之间却并不 “和谐“。因为继承有很多缺点,当子类继承父类时,虽然可以复用父类的代码,但是父类的属性和方法对子类都是透明的,子类可以随意修改父类的成员。如果需求变更,子类对父类的方法进行了一些复写的时候,其他的子类可能就需要随之改变,这在一定程度上就违反了封装的原则,解决的方案就是引入里氏替换原则。
里氏替换原则为良好的继承定义了一个规范,它包含了4层含义:
1、子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
2、子类可以有自己的个性,可以有自己的属性和方法。
3、子类覆盖或重载父类的方法时输入参数可以被放大。
4、子类覆盖或重载父类的方法时输出结果可以被缩小,也就是说返回值要小于或等于父类的方法返回值。
确保程序遵循里氏替换原则可以要求我们的程序建立抽象,通过抽象去建立规范,然后用实现去扩展细节,所以,它跟开闭原则往往是相互依存的。
依赖倒置原则
依赖倒置原则,Dependence Inversion Principle,简称DIP,它的定义是:
抽像的东西,往往少,属于小头,细节的东西很多,属于大头,大头依赖于小头,所以叫倒置
高层模块不应该依赖底层模块,两者都应该依赖其抽象;
抽象不应该依赖细节;
细节应该依赖抽象;
什么是高层模块和底层模块呢?不可分割的原子逻辑就是底层模块,原子逻辑的再组装就是高层模块。
在Java语言中,抽象就是指接口或抽象类,两者都不能被实例化;而细节就是实现接口或继承抽象类产生的类,也就是可以被实例化的实现类。依赖倒置原则是指模块间的依赖是通过抽象来发生的,实现类之间不发生直接的依赖关系,其依赖关系是通过接口是来实现的,这就是俗称的面向接口编程。
接口隔离原则
接口隔离原则,Interface Segregation Principle,简称ISP,其定义是:隔离了不需要的接口。
客户端不应该依赖它不需要的接口
意思就是客户端需要什么接口就提供什么接口,把不需要的接口剔除掉,这就需要对接口进行细化,保证接口的纯洁性。换成另一种说法就是,类间的依赖关系应该建立在最小的接口上,也就是建立单一的接口。
你可能会疑惑,建立单一接口,这不是单一职责原则吗?其实不是,单一职责原则要求的是类和接口职责单一,注重的是职责,一个职责的接口是可以有多个方法的,而接口隔离原则要求的是接口的方法尽量少,模块尽量单一,如果需要提供给客户端很多的模块,那么就要相应的定义多个接口,不要把所有的模块功能都定义在一个接口中,那样会显得很臃肿。
迪米特原则
迪米特原则,Law of Demeter,简称LoD,也被称为最少知识原则,它描述的规则是:
一个对象应该对其他对象有最少的了解
也就是说,一个类应该对自己需要耦合或调用的类知道的最少,类与类之间的关系越密切,耦合度越大,那么类的变化对其耦合的类的影响也会越大,这也是我们面向设计的核心原则:低耦合,高内聚。
迪米特法则还有一个解释:只与直接的朋友通信。
什么是直接的朋友呢?每个对象都必然与其他对象有耦合关系,两个对象的耦合就成为朋友关系,这种关系的类型很多,例如组合、聚合、依赖等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。