面向对象设计7大原则

概述熟练掌握和应用面向对象设计(Object Oriented Design , OOD)7大原则 , 是初/中级JAVA工程师向高级/资深工程师进阶的一个必备技能 , 它可以大大提升程序的可复用性和可维护性 , 也是重构代码的一大利器 。7大设计原则包括开闭原则、里氏替换原则、依赖倒转原则、单一职责原则、接口隔离原则、组合/聚合复用原则、迪米特法则 。
1.开闭原则面向对象可复用设计原则中最基础的原则便是开闭原则(Open-Closed Principle , OCP) 。开闭原则指的是在设计一个对象(类、模块、函数)时 , 应遵循或做到对扩展开放、对修改关闭 , 其核心思想是面向接口/抽象进行编程 。比如第四方支付平台 , 集成微信支付服务时 , 遵循开闭原则的话 , 正常的做法就是先抽象设计一个支付接口 , 然后微信支付类实现该支付接口 。以后平台集成更多如支付宝、华为、苹果等支付服务时 , 只需要扩展一个对应支付方式的支付类即可 , 这样既扩展了新的支付服务 , 同时避免了修改现有的支付接口以及微信支付类 , 最大限度保证了新代码不会影响现有的业务代码 。这就是对扩展(新对象)开放 , 对修改(现有对象)关闭 。
2.里氏替换原则里氏替换原则(Liskov Substitution Principle , LSP)要求设计一个对象时 , 代码中任何父类对象可以出现的地方 , 子类都可以出现 , 即可以使用子类来代替父类 。实现开闭原则的核心思想是面向接口/抽象进行编程 , 其关键步骤是抽象化 , 而父类和子类的继承关系就是抽象化的具体体现 , 所以里氏替换原则是对实现抽象化的具体步骤的规范 , 它是对开闭原则的补充 。比如教学平台中新增加了学生用户Student , 和教师用户Teacher一样进入个人中心 , 都需要登录 , 在设计或重构用户登录服务类时 , 抽象的用户User类作为教师Teacher和学生Student的父类 , 此时需要遵循出现用户User的地方 , 都可以使用新扩展的学生Student代替 , 当然也必须也可以使用教师Teacher代替 , 这样设计出来的User类 , 对用户登录服务类来说 , 后续扩展更多的用户User的子类比如家长、辅导员时 , 可以保证符合开闭原则 。
3.依赖倒转原则依赖倒转原则(Dependency Inversion Principle , DIP)指程序中要依赖抽象(接口/抽象类)而不是具体的实现(实现类)进行编程 , 即面向接口/抽象进行编程 , 这样可以最大程度降低模块之间的耦合 。比如订单服务中 , 会调用(依赖)支付服务以完成订单的支付 。此时的订单服务实现类代码中 , 声明或持有的应该是一个支付服务PayService接口 , 而不是具体实现类比如Alipay或WeChatPay , 所有需要用到支付服务的地方 , 调用的都是PayService接口变量 , 即代码中都是接口 , 等到在运行时才实例化或注入具体的实现类 , 编写代码时不需要关心具体实现类 , 也就是面向接口/抽象编程 。这样 , 在应用程序扩展或集成新的支付服务时 , 原来的订单服务代码可以不需要进行修改任何代码 , 这样也就符合了开闭原则 。
4.单一职责原则单一职责原则(Single Function Principle , SFP)又称单一功能原则 , 它规范设计一个类应只实现单一或独立的职责即业务功能 。职责分明的设计 , 可以提高程序的可维护性 。如果多个独立的业务功能设计在同一类中 , 当一个或多个业务功能扩展或变动需要修改代码时 , 可能会带来冲突问题 , 降低可维护性 。比如订单服务中 , 又包含了用户服务 , 重构用户服务的代码时 , 相当于重构订单服务的代码 , 这是不合理的 , 容易造成混淆 。
5.接口隔离原则接口隔离原则(Inteface Segregation Principle , ISP)指设计时不同的功能应定义在不同的接口上 , 避免实现类依赖不需要的接口 , 换个角度理解就是一个类应该依赖尽量少的接口或实现类 , 减少程序的冗余性和复杂性 。
6.组合/聚合复用原则【面向对象设计7大原则】组合/聚合复用原则(Composition/Aggregation Principle , CARP)也叫做合成复用原则(Composition Reuse Principle , CRP) , 它指在一个新的对象中引入/注入现有的对象以达到功能复用和扩展的目的 。简单讲就是尽量使用组合/聚合而不要使用继承 。


推荐阅读