1.单一职责原则:
定义:应该有且仅有一个原因引起类的变更
好处:
1.类的复杂性降低,实现什么职责都有清晰明确的定义;
2.可读性提高,复杂性降低;
3.可维护性提高,可读性提高;
4.变更引起的风险降低。变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性,维护性都有非常大的帮助
2.里氏替换原则
定义:只要父类能出现的地方子类就可以出现,而且替换成子类也不会产生任何错误或异常
规范:
1.子类必须完全实现父类的方法
2.子类可以实现自己的方法
3.覆盖或实现父类的方法时输入参数可以被放大(子类拥有父类的所有属性和方法,方法名相同,输入参数类型又不相同,是重载)
注意:
子类中方法的前置条件必须和超类中被覆写的方法的前置条件相同或者更加宽松,否则会执行子类的方法会引起逻辑混乱
3.迪米特法则
定义:迪米特法则也称为最少知识原则
一个对象应该对其他对象有最少的了解,通俗地讲,一个类应该对自己需要耦合或调用的类知道最少
迪米特法则对类的低耦合提出了明确的要求
1.只和朋友交流
朋友类的定义:出现在成员变量,方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类
一个类只和朋友类交流,不和陌生类交流,类和类之间的关系应该是建立类之间,而不是方法中间
举个栗子
A类中生产一个数组,传入B类,B类中有一个计算数组长度的方法countSize
class A{
void commond(B b){
List<integer> list = new Arrary();
for(int i =0;i<20;i++;){
list.add(i);
}
b.countSize(list);
}
}
class B{
void countSize(List<integer> list){
System.out.print(list.size)
}
}
A类只有一个B类是朋友类,而list是方法内部的类不算朋友类,而迪米特法则告诉我们
只和朋友类交流,但是定义的commond方法声明了一个list动态数组,这样会破坏A类的健壮性,因为方法是类的一个行为,而类不知道自己的行为和其他类产生了依赖关系,这是违反了迪米特原则的
class A{
void commond(B b){
b.countSize();
}
}
class B{
private List<integer> list;
B(List<integer> list){
this.list = list;
}
void countSize(List<integer> list){
System.out.print(this.list.size)
}
}
这样就可以避免A类对陌生类List的访问,降低了耦合性,提高了系统的健壮性
2.朋友之间也是要有距离的
朋友类尽量不要暴露过多的public方法,因为这会导致类与类之间的耦合性变得很强,后期维护改动上会很难维护,朋友类尽量把可以封装的逻辑封装在自身,这也体现了类的高内聚特性,把封装好的逻辑用一个public方法暴露出去,这样调用类和朋友类的耦合关系会降低,结构也清晰
一个类公开的public属性或方法越多,修改时涉及的面就越大,变更引起的风险扩散也越大
3.是自己的就是自己的
如果一个方法放在本类中,既不增加类间的关系,也不会对本类产生负面影响,就放置在本类中
4.谨慎的使用Serializable
客户端修改了,而服务端没有做出相应的修改,则会报序列化错误,这个问题很少出现,就算出现了也很快会解决
最佳实践
迪米特法则的核心思想就是 类间的解耦,弱耦合,只有弱耦合了以后,类的复用率才会提高,但是会导致产生大量的中转类和跳转类,导致系统的复杂性提高,同时维护带来了困难,采用迪米特法则时,需要反复权衡
迪米特法则要求类间解耦,但是解耦是有限度的,要适度考虑这个原则
4.接口隔离原则
接口分为两种
1.实例接口,在java中类也是一种接口
2.类接口,interface关键字所定义的接口
定义:
客户端不应该依赖它不需要的接口
类间的依赖关系应该建立在最小的接口上
将两句话结合而言就是建立单一接口,不要建立臃肿庞大的接口,再通俗一点而言,接口应该尽量细化,同时接口中的方法应该尽量的少
与单一职责的区别:
单一职责相比和接口隔离原则的审视角度不一样
单一职责原则要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求的是接口的方法尽量少
举个例子:
一个接口可能职责可能包含10个方法,这10个方法都在一个接口中,并且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外通过文档约束“不使用的方法不要访问”,按照单一职责原则是运行的,但是在接口隔离原则是不允许的,因为它要求“尽量使用多个专门的接口”。专门的接口是指提供给每个模块的都应该是单一接口,提供给几个模块就几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端的访问
接口隔离原则是对接口进行规范约束
1.接口要尽量小,不出现臃肿的接口,根据接口隔离原则拆分接口时,首先必须满足单一职责原则
2.接口要高内聚,高内聚就是提高接口,类,模块的处理能力,减少对外的交互。接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越小,同时有利于降低成本
3.定制服务 ,定制服务就是单独为一个个体提供优良的服务
4.接口设计是有限度的
5.依赖倒置原则
1.模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的
2.接口或抽象类不依赖与实现类
3.实现类依赖接口或抽象类
注意:
在java中,只要定义变量就必然要有类型,一个变量可以有两种类型,一个变量可以有两种类型:表面类型和实际类型,表面类型是在定义的时候赋予的类型,实际类型是对象的类型,如zhangsan的表面类型是IDriver,实际类型是Driver
依赖的三种写法:
构造函数传递依赖对象
setter方法传递依赖对象
接口声明依赖对象
1.每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备
2.变量的表面类型尽量是接口或者是抽象类
3.任何类都不应该从具体类派生
4.尽量不要覆写基类的方法
4.结合里氏替换原则使用
6.开闭原则
核心:
对扩展开放,对修改关闭
开闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有代码来完成变化,面向接口编程,扩展时,可以通过继承接口来实现功能的增加
※继承的好处与缺点
好处:
1.代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性
2.提高代码的重用性
3.子类可以形似父类,但又异于父类
4.提高代码的可扩展性
5.提高项目或产品的开放性
缺点:
1.继承是侵入性的,只要继承就必须拥有父类的所有属性和方法;
2.降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束
3.增强了耦合性。当父类的常量,变量和方法被修改时,必须需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能会带来非常糟糕的结果—大量的代码需要重构