一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。用抽象构建框架,用实现扩展细节。
可以提高软件系统的可复用性和可维护性
假设我们有一个课程,课程有名称和价格。但是现在我们有的时候需要对这个课程进行打折出售。
1. 定义一个课程接口
public interface ICourse {
Integer getId();
String getName();
Double getPrice();
}
2. java课程
public class JavaCourse implements ICourse{
private Integer Id;
private String name;
private Double price;
public JavaCourse(Integer id, String name,Double price){
this.Id = id;
this.name = name;
this.price = price;
}
@Override
public Integer getId() {
return this.Id;
}
@Override
public String getName() {
return this.name;
}
@Override
public Double getPrice() {
return this.price;
}
}
3. 定义一个课程优惠的类实现上面那个java课程
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(
Integer id, String name, Double price) {
super(id, name, price);
}
public Double getDiscountPrice(){
return super.getPrice() * 0.6;
}
}
高层的模块不应该依赖低层模块,两者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。
总结一句话,针对接口编程,不要针对实现编程。
还是已课程为例,我们现在不仅仅有java课程,还设有其他的如python。那么应该如何做呢?
1.抽象一个课程接口
public interface ICourse {
void study();
}
2.java课程的实现
public class JavaCourse implements ICourse {
@Override
public void study() {
System.out.println("Sinclair正在学习java课程");
}
}
3.python课程的实现
public class PythonCourse implements ICourse {
@Override
public void study() {
System.out.println("Sinclair正在学习Python课程");
}
}
4. 定义一个学生类
public class Student {
// public void studyJavaCourse(){
// System.out.println("Student正在学习java课程");
// }
//
// public void studyPythonCourse(){
// System.out.println("Student正在学习Python课程");
// }
public void study(ICourse iCourse){
iCourse.study();
}
}
5.定义一个测试类
public class DependenceInversionTest {
public static void main(String[] args) {
Student stu = new Student();
// stu.studyJavaCourse();
// stu.studyPythonCourse();
stu.study(new JavaCourse());
stu.study(new PythonCourse());
}
}
不要存在多余一个导致类变更的原因。一个类,接口,方法只负责一项职责。
还是已课程为例,我们有一个课程,同时我们还要管理这个课程
1.抽象一个课程信息接口
public interface ICourseInfo {
void getCourseName();
void getCourseVideo();
}
2.抽象一个课程管理接口
public interface ICourseManage {
void studyCourse();
void refundCourse();
}
3.定义一个课程类实现这两个接口
public class CourseImpl implements ICourseInfo, ICourseManage {
@Override
public void getCourseName() {
}
@Override
public void getCourseVideo() {
}
@Override
public void studyCourse() {
}
@Override
public void refundCourse() {
}
}
用多个专门的接口,而不是使用单一的接口,客户端不应该依赖它不需要的接口。
注意:
比如说世界上有很多的动物,地上跑的,水里游的
1. 抽象一个动物接口
public interface IAnimal {
void eat();
}
2. 定义一个飞行动物的子接口
public interface IFlyAnimal extends IAnimal {
void fly();
}
3. 定义一个会游泳的子接口
public interface ISwimAnimal extends IAnimal {
void swim();
}
4. 不同的动物去实现不同的子接口
public class Dog implements ISwimAnimal {
@Override
public void eat() {
}
@Override
public void swim() {
}
}
public class Bird implements IFlyAnimal {
@Override
public void eat() {
}
@Override
public void fly() {
}
}
子类可以扩展父类的功能,但不能改变父类原有的功能
待更新
一个对象应该对其他对象保持最少的了解,尽量减少类与类之间的耦合。
降低类之间的耦合
比如领导想知道课程的数量,可以去安排员工去查看
1. 定义一个课程类
public class Course {
}
2. 定义一个员工类,员工持有并可以检查课程数量
public class Employee {
public void checkNumberOfCourse() {
//模拟一下
ArrayList<Course> courses = new ArrayList<Course>();
for (int i = 0; i < 100; i++) {
courses.add(new Course());
}
System.out.println("课程的数量为:" + courses.size());
}
}
3. 领导想知道课程的数量,只需要让员工去检查即可
public class TeamLeader {
public void commandCheckNumber (Employee employee) {
employee.checkNumberOfCourse();
}
}
尽量使用对象组合、聚合,而不是继承关系达到软件复用的目的
可以使用系统更加灵活,降低类与类之间的耦合度
一个类的变化对其他类的影响相对叫小
假设我们想要去连接数据库,添加数据。
1. 抽象一个数据库
public abstract class DBConnection {
public String getConnection() {
return null;
}
}
2. 分别有MySQL数据库和Oracle数据库
public class MySQLConnection extends DBConnection {
@Override
public String getConnection() {
return "获取MySQL连接";
}
}
public class OracleConnection extends DBConnection {
@Override
public String getConnection() {
return "获取Oracle连接";
3. 我们要获取数据库连接的时候,只需要持有他们共同的接口后者抽象类即可
public class ProductDao {
private String dbConnection;
void setConnection(DBConnection dbConnection) {
this.dbConnection = dbConnection.getConnection();
}
void addProduct() {
System.out.println(dbConnection);
}
}