有可能重复别的文章,只是自己的一个整理
单一法则
类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障或者难以维护,这就违背了单一职责
一个类只负责一件事儿,一个方法只负责一件事儿,写了太多的分支判断,去执行各自的业务逻辑时候,就容易出现职责不单一,所以只能拆分解决职责不单一的问题
类拆分:父类+子类,每个类就很简单,类内部很简单,简单就意味着稳定,未定就是开发永恒的追求,拆分以后:代码量就变多了,类增多了,(解读量增大了,理解成本增大了)
如果方法足够简单,类够少,其实违背一下单一职责也无所谓,如果方法多了,业务逻辑复杂,建议遵循单一职责。
方法的单一职责:一个方法只负责一件事儿(根据职责分拆小方法,避免分支逻辑判断)
类的单一职责:一个类只负责一件事儿
类库的单一职责:一个类库应该职责清晰
系统层面的单一职责:为通用的功能分拆系统
优点:
- 降低类的复杂度
- 提高类的可读性,因为类的职能单一,看起来比较有目的性,显得简单
- 提高系统的可维护性,降低变更程序引起的风险
里氏替换原则
任何使用基类的地方,都可以透明的使用其子类
继承:子类拥有基类的一切属性和行为,任何基类出现的地方都可以用子类代替
继承+透明(安全,不会出现行为不一致的情况)
在创建对象的时候尽量使用父类做变量的声明;为了能够更加灵活
继承的优点:
- 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性
- 提高代码的重用性
- 子类可以形似父类,但又异于父类
- 提高代码的可扩展性,实现父类的方法就可以”为所欲为”,很多开源框架的扩展接口都是通过继承父类完成。
继承的缺点:
- 继承是侵入性的。只要继承,就必须拥有父类的属性和方法,如果出现子类不应该有的东西,那就需要断掉继承;(可以再来一个父类,在这个父类里面只包含应该有的东西)
- 降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束
子类出现的地方,父类不一定能够代替。
- 增强了耦合性。当父类的常量,变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果------大段代码需要重构。
迪米特法则
迪米特法则(最少知道原则):一个对象应该对其他对象保持最少的了解
只与直接的朋友通信
尽可能减少对象与对象之间的依赖
因为C#语言是面向对象语言,万物皆对象,各个对象之间的交互才能成各种功能
类和类之间的关系:分为两个维度;
纵向:继承 实现(相似度几乎100%)
横向:依赖(出现在方法中的其他对象)
高内聚低耦合:
迪米特法则:其实就是降低了类之间的耦合
例子:三层(UI层,BLL,DAL)
迪米特法则:依赖别人更少,也让别人了解的更少
优点
迪米特法则的做法观念就是类间的解耦,弱耦合,只有弱耦合了之后,类的复用率才能提高
缺点
造成系统的不同模块之间的通信效率降低,使系统的不同模块之间不容易协调等缺点
因为迪米特法则要求类与类之间尽量不直接通信,如果类之间需要通信就要通过第三方转发的方式,这就直接导致了系统中存在大量的中介类,大大增加了系统的复杂度
解决这个问题的方式是:使用依赖倒置原则(通俗地讲就是针对接口编程,不要针对具体编程),这要就可以是调用方和被调用方之间有了一个抽象层,被调用方在遵循抽象层的前提下就可以自由的变化,此时抽象层成了调用方的朋友
注意事项:
- 在类的划分上,应当创建弱耦合的类,类与类之间的耦合越弱,越有利于实现可复用的目标
- 在类的结构设计上,每个类都应该降低成员的访问权限
- 在类的设计上,只要有可能,一个类应当设计成不变的类
- 在对其他类的引用上,一个对象对其他类的对象的引用应该降到最低
- 尽量限制局部变量的有效范围,降低类的访问权限。
依赖倒置法则
依赖倒置原则是程序要依赖于抽象接口,不要依赖于具体实现.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合
1.每个类尽量都要有接口或者抽象类,或者抽象类和接口都有:依赖倒置原则的基本要求,有抽象才能依赖倒置
2.变量的表面类型尽量是接口或者抽象类
3.任何类都不应该从具体类派生
4.尽量不要重写基类已经写好的方法(里氏替换原则)
依赖倒置原则的核心就是面向抽象(抽象类或接口)编程
接口隔离法则
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上
拆分接口的时候,尽量把动作集中在一起,如果有部分接口功能不完全,可以通过接口的组合(接口之间的继承)
ISP的几个使用原则
根据接口隔离原则拆分接口时,首先必须满足单一职责原则:没有哪个设计可以十全十美的考虑到所有的设计原则,有些设计原则之间就可能出现冲突,就如同单一职责原则和接口隔离原则,一个考虑的是接口的职责的单一性,一个考虑的是方法设计的专业性(尽可能的少),必然是会出现冲突的。在出现冲突时,尽量以单一职责为主,当然这也要考虑具体的情况。
提高高内聚:提高接口,类,模块的处理能力,减少对外的交互,使接口用最少的方法去完成最多的事情。具体来说就是:要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险就越小,也有利于降低成本。
定制服务:单独为一个个体提供优良服务。(只提供访问者需要的方法)
ISP的优点
接口隔离原则是为了约束接口,降低类对接口的依赖性,遵循接口隔离原则有以下5个有点
- 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性
- 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合
- 如果接口粒度大小定义合理,能够保证系统的稳定性l但是如果定义过小,则会造成接口数量过多,使设计复杂化,如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险
- 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义
- 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码
开闭原则
定义:软件实体应该对扩展开放,对修改关闭,是前五大原则的一个总则,其含义是说,一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。
开闭原则的作用
开闭原则是面向对象设计的终极目标,他使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。具体来说,其作用如下:
1.对软件测试的影响
软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍能够正常运行
2.可以提高代码的可复用性
粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。
3.提高软件的可维护性
遵守开闭原则的软件,其稳定性高和延续性强,从而易于维护。
开闭原则的使用
1.抽象约束
1.通过接口或抽象类约束扩展,对扩展进行边界限定, 不允许出现在接口或抽象类中不存在的public方法
2.参数类型,引用对象(调用对象具体方法)尽量使用接口或者抽象类,而不是实现类
3.抽象层尽量保持稳定,一旦确定不允许修改接口或抽象类一旦定义,应立即执行,不能有修改接口的想法,除非是彻底的大返工
2.元数据控制模块行为
元数据:用来描述环境和数据的数据,通俗的说就是配置参数
通过扩展一个子类,修改配置文件,完成了业务的变化,也是框架的好处
3.制定项目章程
4.封装变化
对变化的封装包含两层含义:
1.将相同的变化封装到一个接口或抽象类中
2.将不同的变化封装到不同的接口或抽象类中