总原则:开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。
当我们需要对现有程序进行扩展时,不要去修改之前的代码,应该扩展之前的代码,这样做的好处在于,扩展功能的同时不会影响到之前的程序正常流程,测试也只需要测试扩展的功能。遵守这一原则,我们需要多使用抽象类和接口。
1、单一职责原则(Single Responsibility Principle)
每个类应该只负责完成一项任务,是该类发生改变的原因只有一个。
2、里氏替换原则(Liskov Substitution Principle)
任何基类出现的地方,衍生类都可以替换它,而功能不受影响。
这就要求,子类对父类的方法尽量不要重写,应在基类基础上扩展它。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。
下面示例帮助理解:
package com.yang;
class Math {
public void study(){
System.out.println("学习数学。");
}
}
class Chinese {
public void study(){
System.out.println("学习语文。");
}
}
public class Student {
public void studyMath(Math math){
math.study();
}
}
class Test {
public static void main(String[] args) {
Student student = new Student();
student.studyMath(new Math());
}
}
上述示例中Student
调用Math
的study
方法,看似没有什么问题,但当Student
需要学习Chinese
时需要在Student
中添加studyChinese
方法,这明显违反了开闭原则,可做如下调整:
package com.yang;
interface IStudy {
void study();
}
class Math implements IStudy {
@Override
public void study() {
System.out.println("学习数学。");
}
}
class Chinese implements IStudy {
@Override
public void study() {
System.out.println("学习语文。");
}
}
public class Student {
public void study(IStudy iStudy) {
iStudy.study();
}
}
class Test {
public static void main(String[] args) {
Student student = new Student();
student.study(new Math());
student.study(new Chinese());
}
}
study
的动作具有共性,可以抽象到接口IStudy
中,Student
于上层接口交互(面向接口编程),当需要学习新的课程,我们只需要添加新的课程类,实现IStudy
接口,在调用时通过参数传递的方式指定学习哪一门课程就可以了。
4、接口隔离原则(Interface Segregation Principle)
类不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。这个比较好理解,如果我们只是因为某一个方法依赖于一个较为庞大的接口,我们就需要去实现很多无用的方法,这时应该将这个庞大的接口拆分。
5、迪米特法则(最少知道原则)(Demeter Principle)
一个软件实体应当尽可能少地与其他实体发生相互作用,通过中间类建立联系。过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。
6、合成复用原则(Composite Reuse Principle)
尽量首先使用合成/聚合的方式,而不是使用继承。