---
# System prepended metadata

title: 第六章 物件及資料結構
tags: [Tag(Clean Code)]

---

# 第六章 物件及資料結構

###### tags: `Tag(Clean Code)`

[TOC]

## 大綱

使用私有 (private) 變數的理由是「不希望任何人依賴這些變數」，但是有許多工程師會自動為它們==加上 getter 與 setter，讓私有變數如同公用 (public) 變數一般==。

探討資料結構與物件的不同之處，經常會在寫程式時用到這兩種技巧，但是它們的意義是不一樣的，為了方便管理與維護，必須時時刻刻在意究竟現在寫的是資料結構還是物件。

最後，德摩特爾法則是一種撰寫程式的規範，我們不應該知道太多物件內的事情，否則就會破壞物件的封裝，讓被使用的物件難以被維護。

### 資料抽象化

* 具體：
資料結構，這暴露了程式的實踐過程，這是一個直角座標系。

```
public class Point {
    public double x;
    public double y;
}
```

* 抽象：
將實現的過程隱藏，不只是加上一層函式的介面而已，確切來說這是一種==抽象化的過程==，讓使用者在不需要知道實現的過程狀態下，還能夠操作資料的本質。
```
public class Point {
    double getX();
    double getY();
    void setCartestion(double x, double y);
    double getR();
    double getTheta();
    void setPolar(double r, double theta);
}
```


---

#### 舉例：

* 具體化的交通工具類別
```
FuleTankCapacityInGallons() {
  double getGallonsOfGasoline();
}
```

* 抽象化的交通類別
```
public interface Vehicle {
  double getPercentFuelRemaining();
}
```

兩種差別，最佳的方式使用==抽象化方式讓資料的細節隱藏==，命名表達資料。這並不是透過介面及讀取、設定函式。

嚴謹做法是「資料抽象概念」的方式。
最糟糕做法是get和set方式而已。


### 資料、物件的反對稱性

* 資料結構與物件的差別
解釋資料結構 (Data Structure) 與物件 (Object) 為何不同，而且它們是反對稱性的存在。

* 物件:
物件將它們的資料在抽象層後方隱藏起來，然後將操作這些資料的函式暴露在外。

* 資料結構:
將資料暴露在外且沒有提供有意義的函式，可以直接對資料讀取與寫入。例如：list、dict、set 等


### 舉例

**資料結構寫法**

Geometry類別操控了三種圖形類別，這三種類別是簡單的資料結構

所以的圖形操作行為都定義在Geometry類別裡面。
但如果在==新增一個圖形類別，就必須改變Geometry裡所有函式==。

```
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.141592653589793 ; 
    public double area (Object shape) throws 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(); 
}
```

**物件導向寫法**
```
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 double PI = 3.141592653589793 ;
     public double area(){
        return PI * radius * radius;
    }

}
```
### 總結

* 物件導向: 
容易新增一個新的==類別==，而不用變動已有的函式。
==相反==的新增函式，就必須改變所有的類別。

* 資料結構（結構化）：
容易新增一個新的==函式==，不需要變動已有的資料結構
==相反==的新增資料結構，就必須改變所以函式。

---

### 德摩特爾法則 (The Law of Demeter)

[維基百科說明](https://en.wikipedia.org/wiki/Law_of_Demeter)

模組不應該知道關於它所操作物件的內部運作，一個物件不應該透過存取者暴露其內部結構。

### 舉例

以下違反了德摩特爾法則

因為在getOptions()的回傳物件上，呼叫了getScratchDir()。
還有在getScratchDir()的回傳物件上，呼叫了getAbsolutePath()。

```
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
```
因為在回傳物件上又呼叫了其他方法，因為這個模組知道==ctxt物件含有選項(options)，而選項又包含了暫時目錄(ScratchDir)，暫時目錄又包含了絕對路徑(AbsolutePath)，這裡有著太多的資訊讓一個函式事先知道了==。

如果ctxt、Options、ScratchDir是物件則它的內部應該被隱藏起來，而非暴露在外。

如果它們是資料結構，那在本質上必然會揭露內部的結構，所以法則在這情況並不適用。


### 資料傳輸物件(Data Transfer Object, DTO)

最佳的資料結構形式，是一個類別裡只有公用變數，沒有任何函式。這種資料結構有時被稱為資料傳輸物件或DTO

解析電文資料轉換成可以讀取和設定的物件。

```
public class Bean_Banking_APP1001_1 extends Bean_Base {

	/**
	 * 查詢日期時間
	 */
	public String datetime;

	/**
	 * 截至目前之可用餘額
	 */
	public String bal;

	public String getDatetime() {
		return datetime;
	}

	public void setDatetime(String datetime) {
		this.datetime = datetime;
	}

	public String getBal() {
		return bal;
	}

	public void setBal(String bal) {
		this.bal = bal;
	}

}
```


---


讓每件事情都是一個物件是一個神話。某些時候，你真的只想使用簡單的資料結構，並透過結構化的程式碼來操作這些資料結構。

而德摩特爾法則是一種撰寫程式的規範，我們不應該知道太多物件內的事情，否則就會破壞物件的封裝，讓被使用的物件難以被維護。