以前以为只要用到封装继承多态三大特性,就是面向对象编程了,其实并不是这样的,真正的面向对象设计是要符合下面的五大原则,
单一职责原则(SRP)
开放封闭原则(OCP)
里氏替换原则(LSP)
依赖倒置原则(DIP)
接口隔离原则(ISP)
①单一职责原则(SRP)
在SRP,我们把职责定义为“变化的原因“(a reason for change),如果你能想到多于一个动机去改变一个类,那么这个类就多于一个职责。
举个例子:
1.比如我们写一个求长方形和圆形总面积的类,简单的s1=a*b,s2=πr²,s=s1+s2然后我们输出s就可以了。
2.但是当我们要改变输出的数据,换种形式,可能是Json格式,也可能是HTML格式,于是我们要修改输出的部分。
3.但是当我们又说不求和了,要分别打印长方形和圆形面积,我们又要注释s=s1+a2,又要重新写输出语句。
发现没有?引起我们改变已经写好的类的原因不止一个,所以最好的办法是什么呢?我们写一个计算长方形面积的类,再写一个计算圆形面积的类,再写一个求和类,再写一个输出类
这样不管你这怎么改,我只需要改一小块就行,这就是单一职责原则!
单一职责可以降低耦合性,增强代码的可复用性,降低某个类的复杂度。
②开放封闭原则(OCP)
既开放又封闭,对扩展是开放的,对更改是封闭的。
扩展即扩展现行的模块,当我们软件的实际应用发生改变时,出现新的需求,就需要我们对模块进行扩展,使其能够满足新的需求。更改封闭即是在我们对模块进行扩展时,勿需对源有程序代码和DLL进行修改或重新编译文件。
这个原则对我们在设计类的时候很有帮助,坚持这个原则就必须尽量考虑接口封装,抽象机制和多态技术。如果违反OCP,那么如果程序中的一处改动会产生连锁反应,就会导致一系列相关模块的改动,那么设计就太过僵化。 OCP建议我们应对系统进行重构,那么以后再进行同样改动,只需添加新代码而不必改动已正常运行的代码。在很多方面,OCP都是面向对象设计的核心所在,可增强灵活性、可重用性、可维护性等。
一般而言,无论模块是多么的“封闭“,都会存在一些无法对之封闭的变化,没有对于所有的情况都贴切的模型。所以,必须有策略地对待这个问题。设计人员必须对他所设计的模块应该对哪种变化封闭做出选择,必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。但大多数情况,猜测都是错误的。
③里氏替换原则(LSP)
子类可以替换父类并且出现在父类能够出现的任何地方,这个原则也是在贯彻GOF倡导的面向接口编程,在这个原则中父类应尽可能使用接口或者抽象类来实现。子类通过实现了父类接口,能够替父类的使用地方。
通过这个原则,我们客户端在使用父类接口的时候,通过子类实现,意思就是说我们依赖父类接口,在客户端声明一个父类接口,通过其子类来实现。这个时候就要求子类必须能够替换父类所出现的任何地方,这样做的好处就是,在根据新要求扩展父类接口的新子类的时候而不影响当前客户端的使用。
④依赖倒置原则(DIP)
传统的结构化编程中,最上层的模块通常都要依赖下面的子模块来实现,也称为高层依赖低层。所以DIP原则就是要逆转这种依赖关系,让高层模块不要依赖低层模块,所以称之为依赖倒置原则。
举例:
我吃面条来填饱肚子,高层模块People 的事件(即函数eat)中直接调用了 Noodle的相应动作,第二次,如果将食物换成了Hamburger, People模块也会收到影响,好麻烦,必须改啊。在这个例子中,依赖的功能是啥,是能填饱肚子,管它是面条、汉堡、米饭,重点是能填饱肚子。
于是我们可以修改成这个样子:
⑤ISP 接口隔离原则
这个原则的意思是:使用多个专门的接口比使用单个接口要好的多。
a. 为什么要分离接口
如果客户程序依赖于一个含有它不使用的方法的类,会有如下问题:
1. 如果其他客户程序需要使用该方法并要求要求这个类改变时,就会影响到这个客户程序;
2.这个客户程序不仅需要了解自己需要使用的方法,也需要了解自己不需使用的方法;
3.这个类可能会变得非常庞大,臃肿,变成胖类。
b.怎么分离
1.委托分离接口,即对象适配器
2.多重继承分离接口 (即类适配器)
网友评论