2
public House
{
    WeatherStation station;

    public float getTemp() {
        //Law of Demeter has been violated here
        return station.getThermometer().getTemperature();
    }
}

public House
{
    WeatherStation station;

    public float getTemp() {
        //Law of Demeter has been preserved?
        Thermometer thermometer = station.getThermometer();
        return getTempHelper(thermometer);
    }

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

上記のコードでは、2つの異なるHouseクラスの定義を確認できます。どちらにもgetTemp()関数があり、最初はデメテルの法則に違反しますが、2番目の関数はそれを保持します(Head First Design Patternsの本による)。

問題は、2番目のクラスがデメテルの法則を保持している理由がよくわからないことです。getTemp()関数にはまだstation.getThermometer()呼び出しがあり、これはデメテルの法則に違反しています。「ドットを1つだけ使用する」-ウィキペディアでこれを見つけましたが、これは当てはまる可能性がありますが、さらに詳細な説明が必要です-「特に、オブジェクトは別のメソッドによって返されるメンバーオブジェクトのメソッドを呼び出さないようにする必要があります」(wiki)。

では、2番目のコード例が法律に違反しない理由を誰かが説明できますか?2番目の方法と最初の方法を本当に区別するものは何ですか?

4

2 に答える 2

3

このテーマについては多くの議論があると思いますが、私が解釈すると、デメテルの法則の目的は...

「ステーションから温度計を取得したくない。ステーションから温度を取得したい。」

実際の状況から考えてみてください。あなたは気象観測所を呼び出します、あなたは彼らに「あなたの建物の外にある温度計は何と言っていますか?」と尋ねません。あなたは彼らに「現在の気温は?」と尋ねます。彼らが彼らの建物の外側に取り付けられた温度計を持っているという事実はあなたの心配ではありません。たぶん、彼らは温度計を窓に向けられた赤外線レーザーに置き換えます。それはあなたには関係ありません。彼らが彼らの情報をどのように入手するかはあなたの関心事ではありません、あなたはただ情報が欲しいだけです。

したがって、そのためには、次のような結果になります。

public House
{
    private WeatherStation _station;

    public House(WeatherStation station)
    {
        _station = station;
    }

    public float GetTemperature()
    {
        return _station.GetTemperature();
    }
}

public WeatherStation
{
    private Thermometer _thermometer;

    public WeatherStation(Thermometer thermometer)
    {
        _thermometer = thermometer;
    }

    public float GetTemperature()
    {
        return _thermometer.GetTemperature();
        // This can be replaced with another implementation, or any other
        // device which implements IThermometer, or a hard-coded test value, etc.
    }
}

これにより、いくつかのレベルのネストが発生しますが、少し不快に見えます。ただし、各レベルは現在まったく同じものと呼ばれていますが、少し異なることを意味していることに注意してください。複製されたコードの意味が異なる場合、実際にはコードの重複ではありません。後で次のようなものでチェーンを壊すことができます:

public House
{
    private WeatherStation _station;

    public House(WeatherStation station)
    {
        _station = station;
    }

    public WeatherInfoDTO GetCurrentWeather()
    {
        var info = new WeatherInfoDTO();
        info.Temperature = _station.GetTemperature();
        //...
        return info;
    }
}

public WeatherInfoDTO
{
    //...
}

public WeatherStation
{
    private Thermometer _thermometer;

    public WeatherStation(Thermometer thermometer)
    {
        _thermometer = thermometer;
    }

    public float GetTemperature()
    {
        return _thermometer.GetTemperature();
        // This can be replaced with another implementation, or any other
        // device which implements IThermometer, or a hard-coded test value, etc.
    }

    //...
}

トップレベルを実装にハードコーディングしないことで、Thermometerこのようなものをサポートするための簡単なリファクタリングが可能になります。

于 2011-12-27T16:31:23.457 に答える
1

2番目が違反していないのは、法律の最も厳密な定義によってのみです。私の意見では、その「合法性は疑わしい」:)、ステーションが温度を取得するために温度計を使用しているという発信者の知識を適切に抽象化していないためです。ヘルパーの代わりに、getTemperature()メソッドをステーションに追加して、そこでの温度計の使用をカプセル化することをお勧めします。

つまり、どちらの例もステーションの実装の詳細を認識しているため、ステーションのgetThermometer()メソッドを削除すると両方の例が壊れます。私の意見では、2番目の方が良いと言うことは法律の精神に違反します。

于 2011-12-27T16:29:36.093 に答える