Integrity of Law of Demeter preserved by using helper function (removed two dots)?

徘徊边缘 提交于 2019-12-13 17:09:44

问题


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

In the code above you can see two different House class definitions. Both have getTemp() function, first of which violates Law of Demeter, but second one preservs it (according to Head First Design Patterns book).

The trouble is I don't quite get why second class preservs Law of Demeter, getTemp() function still has station.getThermometer() call, which (should?) violates Law of Demeter. "use only one dot" - I found this on wikipedia, which could be applicable, but I still need more detailed explanation - "In particular, an object should avoid invoking methods of a member object returned by another method" (wiki).

So could anyone explain why the second code example does not violates the law? What truly distinguishes second method from first one?


回答1:


I imagine there's a lot of discussion that can be had on the subject, but as I interpret it the purpose of the Law Of Demeter would be...

"You don't want to get the Thermometer from the Station. You want to get the Temperature from the Station."

Think of it from a real-life situation. You call up the weather station, you don't ask them, "What does the thermometer on the outside of your building say?" You ask them, "What is the current temperature?" The fact that they have a thermometer attached to the outside of their building isn't your concern. Maybe they replace the thermometer with an infrared laser pointed at a window. It doesn't matter to you. How they come by their information isn't your concern, you just want the information.

So, to that end, you'd end up with something like this:

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

This leads to a few levels of nesting, which does appear to be a little distasteful. But keep in mind that each level, while currently called the exact same thing, means something slightly different. It's not really code duplication if the duplicated code has a different meaning. You could later break the chain with something like this:

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

    //...
}

By not hard-coding the top-level to the implementation of a Thermometer you allow for easy refactoring to support something like this.




回答2:


It's only by the most strict definition of the law that the 2nd isn't in violation. In my opinion, its "legality is dubious" :), because you haven't properly abstracted away the caller's knowledge that the station uses a thermometer to obtain the temperature. Instead of the helper, I'd prefer to add a getTemperature() method to the station, encapsulating its use of a thermometer there.

In other words, both examples are aware of the station's implementation details, so removing the station's getThermometer() method will break both examples. To say the second is better kinda violates the spirit of the law, in my opinion.



来源:https://stackoverflow.com/questions/8646799/integrity-of-law-of-demeter-preserved-by-using-helper-function-removed-two-dots

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!