2014年5月16日 星期五

[OOP]Law of Demeter(Least Knowledge)

Law of Demeter又叫做Least Knowledge,這其實是一個軟體設計的守則,簡單來說就是要簡單化Object之間的互動,讓多個Object不要互相相依。使得系統太過於複雜,造成未來維護成本較高。

Law of Demeter訂出了四條守則,限制一個Object內的函式只能呼叫以下這些函式:

  1. Object本身的函式(Class內的成員函式)
  2. 當作參數傳遞進來的Object,可以呼叫傳遞進來Obejct所提供的函式
  3. 自行在函式中建立的物件所提供的函式
  4. Object中本來就包含的Object(也就是HAS-A的關係)

不屬於以上這四種的函式都禁止呼叫。舉例來說,以下這個取得溫度的例子就違反Law of Demeter:

public float getTemp() {
    return weatherStation.getThermometer().getTemperature();
}

以上的例子呼叫的getTemperature()函式是從getThermometer()中所取得,根據Law of Demeter的定義你不能使用某個透過其他函式回傳的物件中的函式。

public float getTemp() {
    Thermometer thermometer = weatherStation.getThermometer();
    return thermometer.getTemperature();
}

這個例子也同樣違反Law of Demeter,因為thermometer是透過其他Object的函式所取得。

public float getTemp() {
    return weatherStation.getTemperature();
}

正解是在weatherStation中加入一個getTemperature()函式用來取得溫度。這樣就有符合Law of Demeter,因為weatherStation是此Object中包含的物件(HAS-A的關係)。

Law of Demeter可以減少Object之間的相依程度,可以減少軟體維護的成本。不過有優點就有缺點,使用此守則會產生出一些包裝用的函式,使用不當會導致開發速度增加,甚至會提昇軟體複雜度。

以下是一個過度包裝的例子,改成這樣雖然沒有違反Law of Demeter,但是沒有什麼意義。

public House {
    WeatherStation station;

    public float getTemp() {
        Thermometer thermometer = weatherStation.getThermometer();
        return getTempHelper(thermometer);
    }

    public float getTempHelper(Thermometer thermometer) {
        return thermometer.getTemperature();
    }
}

其實所有守則都不是強制的,守則是要對整體設計有益時才遵守。其實就和Design Pattern一樣,當你有需要時才使用。否則盲目的套用一堆OOP守則以及Design Pattern只會導致系統變得複雜,不容易理解。

沒有留言:

張貼留言