Clean-Code: 面向过程 PK 面向对象
面向过程:
假设有两个类Square(正方形),Rectangle(长方形) 。代码如下:
如果有一个类Geometry需要计算图形的面积:
假设现在要添加一个Circle(圆形),并且同样需要计算Circle的面积。那么需要做哪些修改:
1:需要添加Circle类,代码如下:
2:因为需要计算Circle的面积,所以Geometry类需要修改
可以看到增加了sharp is Circle 的判断。
假设现在Geometry类不仅仅需要计算面积,还需要计算sharp的周长。
那么Geometry的代码大致如下:
可以发现,Square,Rectangle,Circle这三个类不需要做任何更改。
也就是说当需要添加函数的时候,数据结构不会受到影响。
面向对象:
如果使用面向对象的角度来思考这个问题,那么该怎么处理呢?
基本上有 if else,switch的地方就可以考虑使用策略模式。
首先可以创建抽象类Shape,或者是接口IShape
当然,在这里随便使用哪一个都可以,因为除了计算面积之外,目前不需要继承字段,属性,所以我选择了接口。
Area的名字是面积,不过并没有体现出获取面积这个动作,所以我决定将Area重命名为GetArea或者是CalculateArea
代码如下:
接着创建实现类,Square,Rectangle
Geometry类的实现就比较简单了
同样,如果需要添加一个Circle,然后计算Circle的面积。那么该如何做呢?
很简单,添加一个Circle类就可以了,Geometry不需要任何变化。
也就是说添加数据结构的同时,方法不受影响。
如果现在要添加一个计算周长的方法呢?
首先IShape接口要增加GetPerimeter 方法。
如果现在编译的话,会得到下面的结果:
无法通过编译有2点好处:
- 修改了接口会导致无法通过编译,这是面向过程无法提供的,比如在面向对象的方案中Geometry中的GetPerimeter方法如果忘记了添加Circle的判断,那么编译一样可以通过。
- GetPerimeter方法由类自行管理,复杂度大大下降,代码结构更加清晰。
以Square为例:代码如下:
如果这时候编译,可以发现,可以编译通过。
所以面向对象的特点是修改数据结构的同时,不影响方法,也就是说添加一个类,不会对原系统的方法有影响。
当然在这里Geometry 需要添加GetPerimeter方法: