本篇文章介绍设计模式中的面向对象设计原则。
定义:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中[1]。
可以参考我之前写过的JDBC简介,DBUtil和StudentDao的分工,DBUtil用来管理数据库的连接,StudentDao用来对student表进行增删改查。
定义:软件实体应当对扩展开放,对修改关闭[1]。
如:突然有业务说要对学生的信息进行扩展,要根据学生的成绩进行排名,可以设计一个新的NewStudentDao类继承原有的StudentDao类,但此时就需要将代码重构,将StudentDao设计成接口或者抽象类。
定义:所有引用基类的地方必须能透明地使用其子类的对象[1]。
在使用接口或抽象类的时候能够使用它的子类,用父类定义对象,如:
StudentDao studentDao = new NewStudentDao();
定义:高层模块不应该依赖底层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象[1]。
针对接口编程,而不是针对实现类编程,实现类中应该只实现接口或父类声明过的方法,而不要给出多余的方法,否则调用不了子类中增加的新方法。
如:一个方法要使用StudentDao。
public void fn(StudentDao studentDao){
...
}
可以传StudentDao的实现类NewStudentDao的对象作为参数,由子类对象覆盖父类对象。
在实现依赖倒转原则时,实现类的对象通过依赖注入的方式注入其他对象中。当一个对象要与其他对象发生依赖关系时,通过方法参数类注入所依赖的对象。常用的注入方式有3种,构造方法注入,设值(Setter)方法注入,接口注入。
开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段,它们相辅相成,互相补充,目标一致。
定义:客户端不应该依赖那些它不需要的接口[1]。
控制使用的接口提供的服务,如:StudentDao只要暴露对student表进行增删改查的方法。
定义:优先使用对象组合,而不是继承来达到复用的目的[1]。
如:在StudentService中,需要使用StudentDao中的方法,将StudentDao作为StudentService的成员,而不是StudentService继承StudentDao。父类的改变会影响子类。使用关联关系减少耦合度。复用的时候多用关联关系,少用继承关系。
定义:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位[1]。
如:当学生模块发生修改的时候,尽可能少得影响到其他模块(教师模块)。
只和以下几类对象通信。
以StudentDao类为例:
1、当前对象内部通信。内部方法互相调用。
2、以参数形式传入到当前对象方法中的对象。addStudent(Student student),和Student类的对象通信。
3、当前对象的成员对象。如将StudentDao作为StudentService的成员,StudentService和StudentDao通信。
4、如果当前对象的成员对象是一个集合,那么集合中的元素也都能通信。意思和上一条差不多,自行理解。
5、当前对象所创建的对象。StudentDao中创建的Connection的对象。
[1] 刘伟,胡志刚,阎朝.C#设计模式[M].清华大学出版社,2013