一、单一职责原则
一个类只负责一个功能领域中的相应职责,如果这个类的代码需要改变的时候,只有一个引起它变化的原因。
例如:我们操作数据库的持久层,如UserDao。那么UserDao变化的原因只能是访问数据库User表的需求发生了改变。
好处就是尽可能高的实现了代码的复用。因为我们程序的任何地方需要使用的User表中的数据时,我们只要引入UserDao即可。
二、开闭原则
对扩展开放,对修改关闭。即在不修改原有代码的情况下进行拓展。
例子:设计生物的呼吸,人用肺呼吸,鱼用鳃呼吸。后期又需要加入了厌氧菌进行无氧呼吸。
反例:伪代码如下
if(鱼){
用鳃呼吸;
}else{
用肺呼吸;
}
后期加入厌氧菌的时候,只能修改源代码,违背了开闭原则!
if(鱼){
用鳃呼吸;
}else if(人){
用肺呼吸;
}else{
无氧呼吸;
}
正例:使用抽象类和组合的模式,拓展的时候不需要修改现有类库。
abstract class LivingBeings {
abstract void breathing();
}
public class Fish extends LivingBeings {
@Override
void breathing() {
System.out.println("用鳃呼吸");
}
}
public class Human extends LivingBeings {
@Override
void breathing() {
System.out.println("用肺呼吸");
}
}
class LivingBeingsActivity {
private LivingBeings livingBeings;
void setLivingBeings(LivingBeings livingBeings) {
this.livingBeings = livingBeings;
}
void breathing(){
livingBeings.breathing();
}
}
客户端调用:
public static void main(String[] args) {
LivingBeingsActivity lba = new LivingBeingsActivity();
lba.setLivingBeings(new Human());//这里传入的参数决定了调用的方法。
lba.breathing();
}
后期需要加入厌氧菌的话,继承LivingBeings即可,不需要修改现有的类库。
三、里氏代换原则
1、一个方法定义的方法参数是BaseClass(父类),当传入的参数是SubClass(子类)时,程序不会发生任何错误和异常。那么,我们说这个程序是遵循里氏代换原则的。(反过来则不成立,java编译器会检查一个程序是否符合里氏代换原则的)
2、里氏代换原则是开闭原则的具体实现手段之一。(如上面例子中的lba.setLivingBeings(new Human());,方法参数是父类)
说明: java编译器会检查一个程序是否符合里氏代换原则,是有局限性的。当子类是父类的一个特殊情况,是违反了里氏代换原则的。例如: java.util库中的Properties继承自HashTable,Properties是一种特殊的HashTable,只能String类型的key和value,HashTable可以是任何类型的key-value,所以在有些地方把父类HashTable换成子类Properties是会报错的!
四、依赖倒置原则
1、抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
2、spring中实现的依赖注入,就是遵循了依赖倒置原则。
3、遵循依赖倒置原则,可以表现出java语言的多态性。
五、接口隔离原则
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。也就是尽量提供粒度更小的接口给客户端,也可以称为“定制服务”。
六、合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的。好处就是更加灵活,封装性更好。
七、迪米特法则
1、一个软件实体应当尽可能少地与其他实体发生相互作用,这样可降低系统的耦合度,使类与类之间保持松散的耦合关系。
2、一个类的修改不应该对关联的类造成太大的波及,为了实现这个,我们可以通过引入一个合理的第三者来降低现有对象之间
的耦合度。
迪米特法则,表现为只于朋友通信。对于一个对象,其朋友主要如下:
(1)以参数形式传入当前对象的参数中
(2)当前对象的成员对象
(3)如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
可以看出,创建一个局部对象变量不属于一个对象的朋友,应该尽量避免和这个局部对象变量交互。