1、开闭原则(OCP):对扩展开放,对修改关闭。
理解:能用抽象类的别用具体类,能用接口的别用抽象类。总之一句:尽量面向接口编程。
注意:开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层次模块的变化,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。在业务规则改变的情况下高层模块必须有部分改变以适应新业务,改变要尽量地少,防止变化风险的扩散
2、单一原则(SRP):应该有且只有一个原因引起类的变更。
理解:比如一个Phone类,有Call和Send两个功能,修改Call功能时影响到了Phone类,修改Send功能时也影响到了Phone类,所以这就违背了此原则,应该独立出来,分成一个PhoneCall类实现Call的功能,一个PhoneSend类实现Send的功能。
注意:实际编码中根据实际需求进行最小功能整理,如一个Phone类,可以将Call(打电话)和Send(发短信)功能都实现,但是不要把Navigation(导航)功能也放进来,因为不是所有手机都有导航功能,如果后期业务发生变化,使用没有导航功能的手机就会出现问题。
3、依赖倒置原则(DIP):高层模块不应该依赖于低层模块,二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
理解:指模块间的依赖是通过抽象来发生的,实现类之间不发生直接的依赖关系,其依赖关系是通过接口是来实现的,这就是俗称的面向接口编程。
注意:尽量为每个类提供接口或抽象类,尽量不要从具体类派生子类。
4、接口隔离原则(ISP):客户端不应该依赖它不需要的接口,类间的依赖应该建立在最小的接口上。
理解:比如一个IPhone接口,有Call(打电话)/Send(发短信)/Navigation(导航) 三个功能,现在定义一个诺基亚老人机类NokiaPhone继承IPhone接口,那此处就不合适,因为诺基亚老人机没有导航功能,所以IPhone接口不应该有Navigation。
注意:使用接口时应该建立单一接口,尽量给调用者提供专门的接口,而非多功能接口。此处说的单一并非是只能有一个功能,而是指在一系列相同或相似产品中提炼出适应所有产品的最小功能集合,就像上面事例中的Call/Send功能,是所有手机都具备的功能。
5、迪米特法则(LoD):又称最少知识原则,一个对象应该对其他对象有最少的了解。
理解:比如一个Phone类,它有Call的功能,但是在Call的时候会先去调用一个Communication(通信)方法判断通信是否正常,那Communication方法就不应该暴露给上层知道。
注意:一个类应该对自己需要耦合或者调用的类知道越少越好,被耦合或者调用的类内部和我没有关系,减少不该public的方法,向外提供一个简洁的访问。
6、里氏替换原则(LSP):所有引用基类的地方必须能透明地使用其子类的对象。
理解:建立一个Phone类,再建立一个HWPhone继承自Phone类,那么在使用时可以使用Phone phone=new HWPhone(),也可以 HWPhone phone=new HWPhone(),父类Phone出现的地方可以使用HWPhone代替。
注意:只要父类出现的地方就能使用子类替换,且替换之后不产生任何异常和错误。也就是说子类必须完全实现父类的方法,并且如果有覆盖父类的方法,那么此方法的参数应该大于等于父类方法的参数(Phone里的Call(string tel),那么HWphone的Call(string/object tel)),而返回值应该小于等于父类方法的返回值(Phone里的返回值是object,HWPhone的返回值可以是object/string),除此之外功能上来说也应该保留父类所实现的功能,如Phone中的Call是实现的是打电话,HWPhone中的Call也应该实现打电话,而不是用来发邮件。