Как изменить код так, чтобы он соответствовал закону Деметры - PullRequest
6 голосов
/ 19 апреля 2010
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;  

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

Ответы [ 5 ]

9 голосов
/ 19 апреля 2010

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

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

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

3 голосов
/ 19 апреля 2010

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

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

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 не нужно знать, как сбросить значение, если значение по умолчанию является чем-то другим или его тип изменится в будущем.

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

1 голос
/ 19 апреля 2010

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

Посмотри на это так

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

Как я собираюсь проверить Performance? Я не хочу, чтобы это автоматически создать BigPerformance сделать подключение к базе данных. Давайте пройдем 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.)

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

Загляните в блог Misco Hevery , чтобы узнать больше об этой и других темах.

1 голос
/ 19 апреля 2010
Category cat = new Category();  
cat.Perf.BigPerf.Value = 1.0;  

есть

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

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

.. [M] метод M объекта O может только вызвать методы следующего виды объектов:

  • О себе
  • Параметры М
  • любые объекты, созданные / созданные в M
  • Объекты прямого компонента O
  • глобальная переменная, доступная O, в области видимости M

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

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

0 голосов
/ 19 апреля 2010

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

...