1、开闭原则(开放-封闭原则)
(Open for extension)扩展是开放的
(Closed for modification)更改是封闭的
面对需求,对程序的改动是增加新代码,而不更改现有的代码;在开发过程中,对于设计的 模块应该先猜想最有可能发生的变化的种类,然后构造抽象来隔离变化。
开放-封闭原则是面向对象的核心所在,遵循这个原则可以带来面向对象的巨大的好处,也就是可维护,可扩展,可复用,灵活性好;开发过程中应该对频繁变化的那些部分做出抽象,当然也要拒绝不成熟的抽象。
在修改它的属性的时候
public class person{
public int age=10;
属性访问器
pubic int Age{
get{}
set{}
}
直接制造一个方法进行访问
public void SetAge(iint tmpAge){
this.age=tempAge;
}
}
2、依赖倒置原则
抽象不应该依赖细节,细节应该依赖于抽象
针对接口编程,不需要实现编程;
高层模块不应该依赖底层模块,两个都应该依赖抽象;
抽象不应该依赖细节,细节应该依赖抽象;
目的:避免需求变化导致过多的维护工作
含义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
解决:面向接口编程,使用接口或者抽象类制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
实例:母亲类Mother有讲故事方法TellStory,依赖一个Book类输入,并使用了Book类的getContent方法以便讲故事。那么下次需要母亲讲报纸上的故事、手机上的故事时,原有接口无能为力。这时,抽象一个包含getContent方法的IReader基类,Book、Newspaper、Cellphone各自实现。母亲的TellStory方法接受一个IReader实例,并调用getContent方法即可。
3、单一职责原则(SRP):
就一个类而言,应该仅有一个引起它变化的原因。(ASD)
如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力,这种耦合后导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏。
目的:降低代码复杂度、系统解耦合、提高可读性
含义:对于一个类,只有一个引起该类变化的原因;该类的职责是唯一的,且这个职责是唯一引起其他类变化的原因。
解决:将不同的职责封装到不同的类或者模块中。 当有新的需求将现有的职责分为颗粒度更小的职责的时候,应该及时对现有代码进行重构。当系统逻辑足够简单,方法足够少,子类够少或后续关联够少时,也可以不必严格遵循你SRP原则,避免过度设计、颗粒化过于严重。
实例:电线类Wire为居民供电,电压为220v;但是新的需求增加,电线也输送高压电,电压为200kv,原有电线类可以增加方法实现扩充,这就违背了单一职责原则。可以提供基类,创建两个派生类,居民供电线、高压输电线。
4、里氏转换原则
子类型必须能够替换掉它们的父类型;
只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类能够杂父类的基础上增加新的行为。
目的:避免系统继承体系被破坏
含义:所有引用基类的地方必须能透明地使用其子类的对象。
解决:子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法;子类中可以增加自己特有的方法;当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。如果子类不能完整地实现父类的方法,或者父类的一些方法在子类中已经发生畸变,则建议断开继承关系,采用依赖,聚合,组合等关系代替继承。
实例:已经定义鸟类具有两个翅膀飞的方法;新加入鸵鸟,不会飞,如果覆盖父类的方法,在两个翅膀飞的方法中什么也不做,就违背里氏替换原则,导致所有鸟都不会飞。应该创建并列的两种鸟基类,会飞与不会飞的。前置条件更宽松、后置条件更严格,比如父类返回Map,子类返回HashMap;父类接受HashMap形参,子类接受Map。
5、迪米特法则(Lod)
最少知识原则,主要强调的是类之间的松耦合;在类的设计上,尽量降低成员的访问权限;
类之间的耦合越弱,越有利于复用。
目的:降低类与类之间的耦合
含义:每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
解决:不发生依赖、关联、组合、聚合等耦合关系的陌生类不要作为局部变量的形式出现在类的内部。
实例:校长管理老师,老师管理学生。校长需要全体点名时,首先对老师点名,但是不必通过老师获取学生的信息并点名,而应该让老师对各自管理学生的点名,否则校长和学生之间就发生了原本不必要的耦合,这样当学生类发生变化时,既要修改老师类,也要修改校长类。
6、接口隔离原则(Interface Segregation Principle)
目的:避免接口过于臃肿
含义:客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。
解决:适度细化接口,将臃肿的接口拆分为独立的几个接口。
实例:考试接口,包含考语数外、理化生、政史地等方法。学生类,实现考试接口,参加考试。文科生类、理科生类派生自学生类,实现考试接口时,就都需要实现一些自己不需要的方法(因为文科生不考理化生、理科生不考政史地)。这时,需要对考试接口进行细化,分为基础科考试接口、文科考试接口和理科考试接口;学生类实现基础科考试接口;文科生、理科生另外各自实现文科考试接口、理科考试接口。
7、组合/聚合复用原则(Composite/Aggregate Reuse Principlee CARP) 合成复用原则
目的:防止类的体系庞大
含义:当要扩展类的功能时,优先考虑使用合成/聚合,而不是继承。
解决:当类与类之间的关系是"Is-A"时,用继承;当类与类之间的关系是"Has-A"时,用组合。
实例:如桥接模式,抽象和实现可以独立的变化,扩展功能时,增加实现类即可;比如装饰模式,只需要一个类,即可为一类类扩展新功能。对于显示图形需求,用图形Shape类,和显示Paint类实现。每个Shape类有一个Paint类指针负责图形绘制显示。Paint类派生RedPaint类和BluePaint类,传递给Shape类,实现图形不同颜色绘制,这样图形绘制逻辑和图形绘制实现可独立变化。某天增加需求,所有的绘制需要加边框,可增加PaintDecorator类,派生自Paint基类,每一个PaintDecorator类有一个Paint对象指针,增加虚函数AddedPaint,重写Paint的绘制方法,增加AddedPaint方法的调用。增加BorderPaintDecorator类,派生自PaintDecorator类,重写AddedPaint方法,增加添加绘制边框代码。这样新增加一个类可以对原始所有画笔类的功能进行扩充。