# 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`