# Clean Code - Ch06 資料結構及物件
將實現功能的過程隱藏,就是一種抽象化的過程,提供一個抽象的介面,讓使用者不需要知道怎麼實現功能但還是可將功能實現出來。
大概就是 **結構化程式設計 vs 物件導向程式設計**
[結構化程式設計](http://www.chwa.com.tw/TResource/VS/book2/ch3/3-1.htm)
[物件導向程式設計](https://expect7.pixnet.net/blog/post/38682120-%5B%E7%A8%8B%E5%BC%8F%5D%5B%E6%A6%82%E5%BF%B5%5D-%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%E3%80%82%E4%BB%80%E9%BA%BC%E6%98%AF%E7%89%A9%E4%BB%B6)
## 1. 資料結構 (struct,純model) VS 物件 (介面)
|資料結構|物件導向|
|-|-|
|將資料暴露在外面,而且也沒有提供操作用的函式|將數據隱藏在抽象層(Interface)後面,只將操作函式暴露在外面|
|如果要增加新的function,不會影響到舊的任何東西,但要增加新的class時,就會影響到舊有的function。|如果要增加新的class,不會影響到舊的class。但要增加新的function時,就會影響到所有的class。|
**資料結構:**
``` csharp
public class Square
{
public Point topLeft;
public double side;
}
public class Rectangle
{
public Point topLeft;
public double height;
public double width;
}
public class Circle
{
public Point center;
public double radius;
}
public class Geometry
{
public final double PI = 3.1436;
public double area (Object shape) throw NoSuchShapeException
{
if (shape instanceof Square) {
Square s = (Square) shape;
return s.side * s.side;
} else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle) shape;
return r.height * r.width;
} else if (shape instanceof Circle) {
Circle c = (Circle) shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException ();
}
}
```
**物件導向:**
``` csharp
public class Square implements Shape {
private Point topLeft;
private double side;
public double area () {
return side * side;
}
}
public class Rectangle implements Shape {
private Point topLeft;
private double height;
private double width;
public double area () {
return height * width;
}
}
public class Circle implements Shape {
private Point center;
private double radius;
public final PI = 3.14;
public double area () {
return PI * radius * radius;
}
}
```
## 2. 火車事故 (Train Wreck)
因為代碼看起來像一長串車廂連接再一起,故名為火車事故 (?
``` csharp
String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
```
## 3. 得墨忒耳定律 (Law of Demeter,LoD) a.k.a 最少知識原則 (Principle of Least Knowledge)
*得墨忒耳定律是鬆耦合的一種具體案例,模組不該知道他所操縱的物件的內部運作*
**原則:**
1. 每個單元對於其他的單元只能擁有有限的知識:只能是與當前單元緊密聯繫的單元;
2. 每個單元只能和它的朋友交談:不能和陌生單元交談;
3. 只和自己直接的朋友交談。
基於上述原則,調用Aclass的Bfunc時,只能response以下東西:
1. Aclass
2. 由Bfunc產生的參數
3. Bfunc所接收到的參數
4. Aclass裡面的實體變數(直接定義在Aclass的變數)
根據上述原則,以下這行代碼不符合LoD,因為在getOptions()回來之前就已經知道它裡面有getScratchDir(),甚至還知道更深層的getAbsolutePath()
**因為他不知道後面function response的型別,但如果是同型別就可以**
``` csharp
String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
```
因為在LoD裡面,這些內部資訊應該被隱藏起來,不該暴露在外面,應該要分拆成如下:
``` csharp
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
```
但如果這些Options、ScratchDir、AbsolutePath,都不是物件,而是資料結構的話,
就不會違反LoD
``` csharp
String outputDir = ctxt.Options.ScratchDir.AbsolutePath;
```
[Law of Demeter](https://zh.wikipedia.org/wiki/%E5%BE%97%E5%A2%A8%E5%BF%92%E8%80%B3%E5%AE%9A%E5%BE%8B)
## 4. 混合體
即**半物件半資料結構**,有函式做重要的事,也有公共變數或公共存取器、修改器。使得難以添加新的函式,也難以添加新的資料結構,是一種糊塗的設計,因為作者不確定,它是否需要函式或型態的保護。
``` csharp
public class Member
{
public int Age { get; set; }
public int GetAge() {
return this.Age;
}
public int SetAge(int value) {
this.Age = value;
}
}
```
## 總結
在設計系統時,我們有時候需要**增加新資料型態的彈性**,這時我們比較需要使用物件導向的設計。
但有時候,我們希望可以有**增加新行為的彈性**,這時我們比較傾向採用資料結構的設計。
###### tags: `Clean Code` `Book`