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();
    }
}

在上面的代码中,您可以看到两个不同的 House 类定义。两者都有 getTemp() 函数,第一个违反了得墨忒耳定律,但第二个保留了它(根据 Head First Design Patterns book)。

问题是我不太明白为什么二等舱保留得墨忒耳定律,getTemp() 函数仍然有 station.getThermometer() 调用,这(应该?)违反了得墨忒耳定律。“只使用一个点” - 我在维基百科上找到了这个,它可能适用,但我仍然需要更详细的解释 - “特别是,一个对象应该避免调用由另一个方法返回的成员对象的方法”(wiki)。

那么谁能解释为什么第二个代码示例不违反法律?第二种方法与第一种方法的真正区别是什么?

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.
    }

    //...
}

通过不将顶层硬编码到 a 的实现中,Thermometer您可以轻松地重构以支持类似的东西。

于 2011-12-27T16:31:23.457 回答
1

只有根据最严格的法律定义,第 2 条不违反。在我看来,它的“合法性值得怀疑”:),因为您没有正确地抽象出呼叫者的知识,即车站使用温度计来获取温度。而不是助手,我更愿意向工作站添加一个 getTemperature() 方法,将其对温度计的使用封装在那里。

换句话说,两个示例都知道工作站的实现细节,因此删除工作站的 getThermometer() 方法将破坏这两个示例。在我看来,说第二个更好有点违反法律精神。

于 2011-12-27T16:29:36.093 回答