Я полагаю, что по этому вопросу можно много спорить, но, как я понимаю, цель Закона Деметры была бы ...
"Вы не хотите получатьТермометр со станции. Вы хотите получить температуру со станции. "
Подумайте об этом в реальной ситуации.Вы вызываете метеостанцию, вы не спрашиваете их: «Что говорит термометр снаружи вашего здания?»Вы спрашиваете их: «Какова текущая температура?»Тот факт, что у них есть термометр, прикрепленный к внешней стороне их здания, вас не касается.Возможно, они заменили термометр инфракрасным лазером, направленным на окно.Это не имеет значения для вас.То, как они получают свою информацию, вас не волнует, вам просто нужна информация.
Итак, с этой целью вы получите что-то вроде этого:
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
, вы обеспечите простой рефакторинг для поддержки чего-то подобного.*