Как изменить код так, чтобы он придерживался Закона Demeter

public class BigPerformance  
{  
    public decimal Value { get; set; }
}  

public class Performance  
{  
    public BigPerformance BigPerf { get; set; }
}  

public class Category    
{  
    public Performance Perf { get; set; }     
}

Если я звоню:

Category cat = new Category();  
cat.Perf.BigPerf.Value = 1.0;  

Я принимаю это, это нарушает закон Demeter / Принцип Наименьшего количества Знания?
Если так, как я исправляю это, если у меня есть большое количество внутренних свойств класса?

6
задан Spoike 19 April 2010 в 11:45
поделиться

5 ответов

Одна из моих любимых цитат Мартина Фаулера:

Я бы предпочел, чтобы это называлось Иногда полезным предложением Деметры

http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx

9
ответ дан 8 December 2019 в 17:19
поделиться

Если вы говорите о Законе Деметры, например, «не называйте соседей соседей», вы можете делегировать его другим методам, которые делают то, что вы хотите.

Из вашего примера я предполагаю, что вы хотите сбросить значение производительности или что-то в этом роде. Вы можете изменить пример кода, чтобы вместо этого они были связаны цепочкой:

Category cat = new Category();

cat.resetPerf();

Код будет примерно таким:

public class BigPerformance 
{
    //constructors 'n stuff

    public static decimal DEFAULT;

    public decimal Value {get; private set;}

    public void reset() {
        Value = BigPerformance.DEFAULT;
    }
}

public class Performance
{
    //constructors 'n stuff

    private BigPerformance BigPerf {get; set};

    public reset() {
        BigPerf.reset();
    }
}

public class Category
{
    // constructors 'n stuff

    public Performance Perf {get; private set;}

    public resetPerformance() {
        Perf.reset();
    }
}

Таким образом, классу Category не нужно знать, как сбросить значение на случай, если значение по умолчанию будет другим или его тип будет изменен в будущем.

Лично я бы предпочел ответ Джухарра , если риск изменений невелик.

3
ответ дан 8 December 2019 в 17:19
поделиться
Category cat = new Category();  
cat.Perf.BigPerf.Value = 1.0;  

is

Category cat = new Category();  
cat.GetPerf().GetBigPerf().SetValue(1.0);  

Таким образом, это нарушает правила, если определение в Википедии правильное:

.. [M] этод M объекта O может только {{1} } вызывают методы следующих типов объектов:

  • O самого
  • M's parameters
  • любых объектов, созданных / созданных в пределах M
  • O прямых компонентных объектов
  • глобальная переменная, доступный для O, в области M

В частности, объект должен избегать вызова методов объекта-члена, возвращаемого другим методом

. Если вас беспокоит, что эти 3 тесно связаны, удалите общедоступные методы доступа и добавьте метод для категории, чтобы установить значение. Затем выполните рефакторинг Performance и BigPerformance, сделав их закрытыми членами.

1
ответ дан 8 December 2019 в 17:19
поделиться

Если вы всегда помните о тестируемости ваших классов и используете IoC, вы заметите, что вам не нужно так сильно беспокоиться о LoD.

Посмотрите на это с другой стороны

Как я собираюсь протестировать Категория ? Я не хочу, чтобы она автоматически создавала Производительность при использовании медленной файловой системы . Давайте передадим IPerformance в Category и заменим фактическую реализацию фиктивным экземпляром Performance . .

Как мне протестировать Performance ? Я не хочу, чтобы он автоматически создавал BigPerformance , создающий { {1}} подключение к базе данных. Давайте передадим IBigPerformance в Performance и заменим фактическую реализацию фиктивной Экземпляр BigPerformance .
...
вы, очевидно, заметили шаблон

Ваш код будет в строке

BigPerformance BigPerf = new BigPerformance();
BigPerf.Value := 1.0;
Performance Perf = new Performance(BigPerformance);
Category cat = new Category(Performance);

(This would be retrieved from a factory.)

Похоже (и, вероятно, в сокращенном варианте) требуется гораздо больше работы, но Преимущества окупятся в долгосрочной перспективе, если вы сможете тестировать свои классы изолированно.

Взгляните на блог Миско Хевери , чтобы получить информацию по этому и другим вопросам.

1
ответ дан 8 December 2019 в 17:19
поделиться

Это не нарушение Закона Деметры, потому что вы используете публичный контракт классов.

0
ответ дан 8 December 2019 в 17:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: