[Clean Code] Chapter 6: 數據結構 vs 對象!

chapter 6: Objects & Data Structures


1-數據抽象

比較一下代碼:

// 代碼1
public class Point {
    public double x;
    public double y;
}

VS

// 可表示極座標系 和 直角座標系的點
// 它不止是一個數據結構,因爲他定義了關於數據的訪問
public interface Point {
    double getX();
    double getY();
    void setCartesian(double x, double y);
    double getR();
    double getTheta();
    void setPolar(double r, double theta);
}

隱藏實現不是僅僅用一層函數把變量隱藏起來(e.g. set/get),而是抽象!!!

在抽象接口中,我們不想將數據的詳細暴露出來,而想以抽象的方式表達我們的數據。
如以下代碼

// 代碼2
public interface Vehicle {
    double getFuelTankCapacityInGallons();  // 獲取總容量
    double getGallonsOfGasoline(); // 獲取汽油量
}

VS

public interface Vehicle {
    double getPercentFuelRemaining(); // 獲取汽油剩餘百分比
}

2-面向過程和麪向對象的對立

對象將自己的數據隱藏了起來,而把對數據操作的函數暴露出來。而數據結構將數據直接暴露出來,沒有任何操作數據的方法(e.g. C語言的struct)。

  • 面向對象: 添加新類別不改變已有函數, 添加新函數會改變所有現有類別
  • 面向過程(數據結構): 添加新函數不會改變現有數據結構, 添加新的數據結構需要改變所有函數。

代碼示例:

// 代碼3
// 面向過程,添加新函數,不要改變舊數據結構
// 添加新類型,需要改變函數

// 類別1
public class Square {
    public Point topLeft; public double side;
}

// 類別2
public class Rectangle {
    public Point topLeft;
    public double height;
    public double width;
}

// 類別3
public class Circle {
    public Point center;
    public double radius;
}

public class Geometry {
    public final double PI = 3.141592653589793;

    // 函數1
    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();
    }
}

3-Data Transfer Objects: DTO (只含public變量,不含function)

爲了OO思想,很多時候寫出了不必要的代碼,如下

// 代碼4
// 一個只含有數據不含有操作的類,爲了OO, 加了getters&setters
public class Address {
    private String street;
    private String streetExtra;
    private String city;
    private String state;
    private String zip;

    public Address(String street, String streetExtra,
                   String city, String state, String zip) {
        this.street = street;
        this.streetExtra = streetExtra;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }

    public String getStreet() {
        return street;
    }

    public String getStreetExtra() {
        return streetExtra;
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

    public String getZip() {
        return zip;
    }
}

4-Active Record(對數據庫表映射的類)

Active Records是一種特殊的DTO, 所有數據都是public, 但是它有find和save方法,用來表示數據庫的操作。把他們當做數據結構,而不是對象;不要試圖在其中加入其他東西,使其變得既不是structure, 也不是objects, 而且還擁有兩者的缺點,修改函數要修改類,添加類又要修改函數


5-總結

  • object: 暴露操作函數,隱藏數據;添加新類別不改變已有函數, 添加新函數會改變所有現有類別
  • data structure: 暴露數據,沒有真正意義的操作函數。添加新函數不會改變現有數據結構, 添加新的數據結構需要改變所有函數。

我們應當根據項目的實際情況選擇他們。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章