面向对象设计原则为支持可维护性复用而诞生这些原则蕴含在很多设计模式中它们是从许多设计方案中总结出的指导性原则。单一职责原则单一原则Single Responsibility Principle,SRP是最简单的设计原则它用来控制类的颗粒度大小。RoleDataOperation类承载了数据库连接、数据库数据操作、存档数据业务操作的功能职责不符合单一职责。下面来改进一下。开闭原则开闭原则(Open-Closed Principle ,OCP)是面向对象的可复用设计的第一块基石它是最重要的面向对象设计原则。在开闭原则的定义中软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类。开闭原则就是指软件实体尽量在不修改源码的情况下进行扩展。开闭原则是评价基于某个设计模式设计的系统是否具备灵活性和可扩展性的重要依据。下面来模拟一个刷怪塔createMonster用如下实现代码此时如果新增一种类型的怪物那么必然会修改createMonster的业务逻辑不符合开闭原则下面来来修改一下。里氏替换原则如果对每一个类型为S的对象o1都有类型为T的对象o2使得以T定义的所有程序P在所有的对象o1代换o2时程序P的行为没有变化那么类型S是类型T的子类型。这个定义比较拗口且难以理解因此我们一般使用它的另一个通俗版定义所有引用基类父类的地方必须能透明地使用其子类的对象。里氏代换原则告诉我们在软件中将一个基类对象替换成它的子类对象程序将不会产生任何错误和异常反过来则不成立如果一个软件实体使用的是一个子类对象的话那么它不一定能够使用基类对象。在程序中尽量使用基类类型来对对象进行定义而在运行时再确定其子类类型用子类对象来替换父类对象。兼容LSP设计原则的execute方法/ 创建Audio产品对象 Product* audio new Audio(); audio-setFilePath(audio.mp3); / 创建Video产品对象 Product* video new Video(); video-setFilePath(video.mp4); / 呼叫下载方法下载不同的产品 download(audio); download(video);不兼容LSP设计原则/ 创建Chocolate产品对象 Product* chocolate new Chocolate(); chocolate-setFilePath(Chocolate can not be downloaded.); / 呼叫下载方法下载巧克力产品 download(chocolate);TIP现在的问题是谁应该对违反LSP负责是download() 函数的创建者吗是产品类的创造者吗还是巧克力类的创造者TIP常见的LSP违规子类中的退化方法如果基类有一个方法但基类的子类不需要该方法那么如果子类的作者再次退化该方法这将是可替代的违规。从子类抛出异常LSP违规的另一种形式是向子类添加异常而基类不希望这样。因为那时基类不能被子类替代。依赖倒置原则如果说开闭原则是面向对象设计的目标的话那么依赖倒置原则Dependence Inversion Principle,DIP就是面向对象设计的主要实现机制之一它是系统抽象化的具体实现。依赖倒置原则定义如下高层模块不应该从低层模块导入任何东西两者都应该依赖于抽象。抽象不应该依赖于细节细节应当依赖于抽象。即针对接口编程而不是针对实现编程。依赖倒置原则要求我们在程序代码中传递参数时或在关联关系中尽量引用层次高的抽象层类即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明以及数据类型的转换等而不要用具体类来做这些事情。为了确保该原则的应用一个具体类应当只实现接口或抽象类中声明过的方法而不要给出多余的方法否则将无法调用到在子类中增加的新方法。在实现依赖倒置原则时我们需要针对抽象层编程而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中依赖注入是指当一个对象要与其他对象发生依赖关系时通过抽象来注入所依赖的对象。常用的注入方式有三种分别是构造注入设值注入Setter注入和接口注入。构造注入是指通过构造函数来传入具体类的对象设值注入是指通过Setter方法来传入具体类的对象接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型在运行时再传入具体类型的对象由子类对象来覆盖父类对象。上面示例中DataBiz是典型的针对具体实现进行编程因此在数据格式变更的时候就需要反复的修改代码。下面进行重构。基于依赖倒置原则新增一个抽象的转换器DataConvertDataBiz针对DataConvert进行编程然后根据里氏替换原则程序运行时对父类进行替换根据开闭原则将运行对象指定设置到配置文件中。在上述重构过程中我们使用了开闭原则、里氏代换原则和依赖倒转原则在大多数情况下这三个设计原则会同时出现开闭原则是目标里氏代换原则是基础依赖倒转原则是手段它们相辅相成相互补充目标一致只是分析问题时所站角度不同而已。接口隔离原则客户端不应该依赖哪些它不需要的接口。根据接口隔离原则当一个接口太大时我们需要将它分割成一些更细小的接口使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色不干不该干的事该干的事都要干。“接口”两种不同的含义一种是指一个类型所具有的方法特征的集合仅仅是一种逻辑上的抽象。在ISP可以理解成一种角 色一个接口只能代表一种角色此时也可以称之为“角色隔离原则”一种是指某种语言具体的“接口”定义有严格的定义和结构如Java中的interface。在ISP中表 达的意思是指接口仅仅提供客户端需要的行为客户端不需要的行为则隐藏起来应当为客户端提 供尽可能小的单独的接口而不要提供大的总接口。根据接口隔离原则重构在使用接口隔离原则时我们需要注意控制接口的粒度接口不能太小如果太小会导致系统中接口泛滥不利于维护接口也不能太大太大的接口将违背接口隔离原则灵活性较差使用起来很不方便。一般而言接口中仅包含为某一类用户定制的方法即可不应该强迫客户依赖于那些它们不用的方法。组合复用原则组合复用原则