OOP-Six-Principles

Just my point

Posted by PfCStyle on November 14, 2016

面对正确的事物,我们往往无法确定它是正确的

面向对象的六大原则

单一职责原则(Single Responsibility Principle)

这一原则虽然简单,但其实争议最大,也是最难以界定的。一个类只应该做自己职责范围内的事,这个职责本身就很难确定,是功能职责?是架构职责?还是其他什么职责?每一个程序员心中可能都有不同的界定。

假定我们以功能职责为标准,类比经理(一般manager类),作为一把手,是不是什么事都要亲自去做?那么其实其他人(财务,市场等)的职能是否都属于经理呢?这样显然不合理,各种事都该各个部门分别去做,然后经理来同意指挥协调(manager去调用各个实现类的方法)。

其实这是六大原则中的另外一种原则了,我想说的事,这个原则,大家需要靠自己的实践经验去形成自己的风格,没有真正的对错,只要你的风格稳定不变。

开闭原则(Open Close Principle)

这也是一个很基础的设计原则,对扩展,开放;对修改,封闭。

一个项目,免不了维护和升级。而在维护升级时,为了避免引入新的bug,我们应该尽量扩展新的功能,而不是直接在旧代码中进行修改。

当然,这只是理想的情景,实际上我们很多时候都不得不去修改旧的代码。但我们也应该尽可能的避免。

避免的方法就是使用开闭原则,尽可能的去覆写父类的方法,或者尽可能的去设计公共接口,然后去实现它们。

里氏替换原则(Liskov Substitution Principle)

简单来说,在我们进行组合依赖时,应该尽可能的依赖的是借口或者父类(包括抽象类),这样我们在覆写了父类或者是实现类借口的方法之后,就可以在使用时随意的替换。

比如现在经理辞职换了一个人,经理职权不变,但是每个人行使职权的风格和方式却是不同的,这个经理只需要重新实现接口,就可以用自己的风格去快速执掌公司类。

依赖倒置原则(Depedence Inversion Principle)

这个,简单解释就是接口去决定细节实现。高层次的模块不去关心低层次的细节实现,而是设计类各种接口去掉用。而低层次模块则是根据高层次的调用的接口去实现细节。

比如,经理管理财务方面,要看财务报表,于是定义了一个看财务报表的接口,那么下面的财务部就得去实现这个接口,提供财务报表。至于这个财务报表,是机器统计的还是会计自己画的,经理是不会关心的。

接口隔离原则(InterfaceSegregation Principles)

这其实就是解决第一个原则中提出的问题,接口应该尽可能的小。

你不能设计一个大的经理的接口,里面声明类各个部门的所有方法,而是应该分成多个接口,每一个接口再去声明各自的功能。甚至,你应该再去进一步细分,比如每个部门有一个总管,下面各个职员,负责各个细节。

迪米特原则(Law of Demeter or Least Knowledge Principle)

一个对象,应该对所依赖的对象有最少的了解。简单来说,你最好就不要了解,各个功能都在对方的类中实现,你只管调用这个函数就好了。

比如,经理现在要市场部提供公司最大的客户的相关信息给他,市场部内有一个列表,保存了所有客户的信息。这时候,应该是市场部内部进行筛选拿到最大客户信息返给经理,而不是经理自己取出市场部的所有客户信息,自己遍历一遍拿出最大客户信息。

怎么看呢

这些原则都是老生常谈了,今天我并不是为了再次介绍它们,而是想说说以前自己的困惑,自己的想法,但,只是自己的观点,谈不上对错。

维护与实现

这是我刚开始接触各种设计模式最大的困惑,我知道怎么去设计架构以符合设计模式,也知道,写出的代码,应该扩展性好,解耦好,健壮性好……可是,一味的去符合设计模式,导致的结果可能会是,代码可读性差,难以维护。这个可能有争论,实际上,这里讨论的是设计模式的使用的度的问题。

比如,你大量的使用接口,那么,你在调试代码时,可能并不知道它到底是那一个子类实现的功能,你还需要按图索骥,一层层的去寻找调用赋值的位置,去寻找到实现的位置,然后再去分析有没有bug。

比如,按照接口隔离原则,可能每一个功能,都要去单独设计一个接口,那么,不可避免的是,你将会分成很多很多类文件,这对于维护来说,也无疑是增加了很大难度。

……

所以,现在是一个如何适度的问题。到底是不是每一个功能都需要单独设计一个接口,到底是不是每一个地方都需要这么好的扩展性,都需要使用父类,接口,抽象类?

程序员都知道,我们应该根据需求来说事。虽然从来都没遇到不变的需求,但是,好在大方向总是不变的,所以需求还是具有一定的参考性的。

那么,根据需求,以及我们的经验,我觉得,模块化的东西,往往需要充分的解耦合,并且应该有好的扩展性。因为我们可能在很多地方使用,以及本项目之外;大而全的东西,可以牺牲这些特性,因为它们可重用的机会比较少,比如android的activity,ios的controller。

总之,需要变化的地方,才是导致工程覆灭的潜在因素,我们的设计模式,我们的软件工程,针对的,应该是这些地方。