Re: Закон Деметера на практике
От: Janii  
Дата: 19.02.07 10:40
Оценка: 2 (1)
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>Как вы считаете, какой из вариантов более аккуратный? Какой облегчает поддержку и дальшейшие изменения программы?


Это зависит от задачи, IMHO. Абстрактно дать лучший ответ сложно, но я бы, в тех условиях что даны, по умолчанию считал лучшим вот такой вариант:

void обслуживание(Машина машина){
   машина.НакачатьКолеса(); 
}


MP>Надо ли стремиться к выполнению закона Деметера, или это "шашечки"?


Стремиться надо, но важно не переусердствовать. Минимизация связывания — это дорогостоящая операция и затраты на нее далеко не всегда оправданы.
Re: Закон Деметера на практике
От: Miroff Россия  
Дата: 20.02.07 07:34
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>Аргументация в том, что уменьшается связанность и упрощается изменение классов. Но мне вот что непонятно. Если мне в метод, например, передается объект "Машина", у которой надо накачать колеса, как лучше поступить?


Не передавать в метод обслуживание экземпляр машины. Поскольку метод "обслуживание" потенциально машино-зависим разумно делегировать эту функциональность машине:
class Машина {
  void обслуживание() {
      self.ЛевоеПереднееКолесо.накачать();
    }
}
Машина машина = Машина.new();
машина.обслуживание();


В будущем, метод обслуживание может сильно распухнуть, тогда потребуется оставив базовые операции вида "НакачатьКолеса" или "ПротеретьФары" применить паттерн Strategy.

MP>Как вы считаете, какой из вариантов более аккуратный? Какой облегчает поддержку и дальшейшие изменения программы? Надо ли стремиться к выполнению закона Деметера, или это "шашечки"?

Закон Деметра позволяет избежать длинных цепочек делегации вида "машина.правоеПереднееКолесо.накачать". Такие цепочки череваты ошибками, небезопасны (кто сказал что у машины есть правое колесо?) и черезмерно усложняют код (если проверять существование колеса)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Закон Деметера на практике
От: Mikhail Polykovsky Россия  
Дата: 20.02.07 07:41
Оценка:
MP>>Аргументация в том, что уменьшается связанность и упрощается изменение классов. Но мне вот что непонятно. Если мне в метод, например, передается объект "Машина", у которой надо накачать колеса, как лучше поступить?

M>Не передавать в метод обслуживание экземпляр машины. Поскольку метод "обслуживание" потенциально машино-зависим разумно делегировать эту функциональность машине


Хорошо, этот пример я понял. А что делать в случае необходимости фильтра
Автор: Mikhail Polykovsky
Дата: 18.02.07
? Тоже закладывать его в класс Машина? Или в класс Колесо?
Re[3]: Закон Деметера на практике
От: Miroff Россия  
Дата: 20.02.07 08:16
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>Хорошо, этот пример я понял. А что делать в случае необходимости фильтра
Автор: Mikhail Polykovsky
Дата: 18.02.07
? Тоже закладывать его в класс Машина? Или в класс Колесо?

Машина не осведомлена о наличии других мащин, равно, как и колесо не осведомлено о наличии других колес. Фильтрами должна заниматься коллекция машин или та прослойка, которая достает машины из БД, файлов и т.п. В этом случае, да, машины должны предоставлять этой коллекции/прослойке информацию о своих свойствах.
class СписокМашин {
  СписокМашин фильтрПоТипуКолеса( типКолеса ) {
      //Здесь мы генерим запрос или нашу перебираем коллекцию машин
        //Например:
        СписокМашин совпадение = СписокМашин.new()
        foreach машина in self.список {
            if (машина.типКолес == типКолеса) {
                совпадение.push(машина)
            }
        }
        return совпадение
    }
}

списокМашины.фильтрПоТипуКолеса( Шипованный );
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Закон Деметера на практике
От: Mikhail Polykovsky Россия  
Дата: 20.02.07 08:37
Оценка:
MP>>Хорошо, этот пример я понял. А что делать в случае необходимости фильтра
Автор: Mikhail Polykovsky
Дата: 18.02.07
? Тоже закладывать его в класс Машина? Или в класс Колесо?

M>Машина не осведомлена о наличии других мащин, равно, как и колесо не осведомлено о наличии других колес. Фильтрами должна заниматься коллекция машин или та прослойка, которая достает машины из БД, файлов и т.п. В этом случае, да, машины должны предоставлять этой коллекции/прослойке информацию о своих свойствах.

M> if (машина.типКолес == типКолеса) {


И вот здесь, насколько я понимаю, нарушается закон Деметера? Это самый оптимальный вариант?
Re: Закон Деметера на практике
От: MaximVK Россия  
Дата: 20.02.07 08:51
Оценка: 3 (2)
Здравствуйте, Mikhail Polykovsky, Вы писали:

3-й вариант. За исключением того, что "левоеПереднееКолесо" — не очень удачный вариант. Т.к. машины могут обладать разным количеством колес и придется писать разные "обслуживания". Т.е. возможность получить колеса в виде коллекции у тебя явно напрашивается. Что касается дальнейших изменений, то тут вариантов может быть много. Что может меняться? Понадобиться качать не только колеса, а еще и шарики, надувные лодки и брюшной пресс? Придется обслуживать не только машины, а велосипеды, тракторы или самолеты? Появяться машины с самоподкачивающимися колесами или детские велосипеды с колесами из сплошной резины? Будешь учитывать все варианты — сделаешь супергибкое решение, но просядешь по срокам так, что твое решение уже нафиг никому не будет нужно. Не учтешь какого-нить варианта, потеряешь клиентов из-за тормозов с кастомизацией или расширением функциональности. Идеальной стратегии нет и это исключительно хорошо, т.к. именно благодаря этой неопределенности и существует возможность у маленькой компании из 5 человек сделать продукт, который станет лучшим на рынке.

P.S. Кстати, был у меня коллега, который в оголтелой погоне за соблюдением закона Дементора наплодил такое количество врапперов по проекту, что их стало чуть ли не больше, чем обычных классов.
Re[5]: Закон Деметера на практике
От: Miroff Россия  
Дата: 20.02.07 08:56
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>И вот здесь, насколько я понимаю, нарушается закон Деметера? Это самый оптимальный вариант?

Или я что-то не так понимаю, или не нарушается:

Любой метод объекта должен обращаться только к методам, принадлежащим:
— тому же классу
— любым объектам, переданным в метод в качестве аргументов
— любым создаваемым им объектам
любым непосредственно содержащимся объектам компонентов


Этот закон можно грубо переформулировать как "никаких ссылок через две точки".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Закон Деметера на практике
От: MaximVK Россия  
Дата: 20.02.07 09:06
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Этот закон можно грубо переформулировать как "никаких ссылок через две точки".


Почти так. В оригинале звучит "не общайтесь со странниками".
Re[5]: Закон Деметера на практике
От: Miroff Россия  
Дата: 20.02.07 09:10
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>И вот здесь, насколько я понимаю, нарушается закон Деметера? Это самый оптимальный вариант?

Или я что-то не так понимаю, или не нарушается:

Любой метод объекта должен обращаться только к методам, принадлежащим:
— тому же классу
— любым объектам, переданным в метод в качестве аргументов
— любым создаваемым им объектам
любым непосредственно содержащимся объектам компонентов


Этот закон можно грубо переформулировать как "никаких ссылок через две точки".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Закон Деметера на практике
От: Mikhail Polykovsky Россия  
Дата: 20.02.07 09:12
Оценка:
MP>>И вот здесь, насколько я понимаю, нарушается закон Деметера? Это самый оптимальный вариант?
M>Или я что-то не так понимаю, или не нарушается:

M>

M>Любой метод объекта должен обращаться только к методам, принадлежащим:
M>— тому же классу
M>— любым объектам, переданным в метод в качестве аргументов
M>— любым создаваемым им объектам
M>— любым непосредственно содержащимся объектам компонентов


M>Этот закон можно грубо переформулировать как "никаких ссылок через две точки".


Любую ссылку через две точки можно развернуть в две ссылки с одной точкой, используя временную переменную. В чем же тогда смысл?
Re[7]: Закон Деметера на практике
От: Miroff Россия  
Дата: 20.02.07 09:21
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>В чем же тогда смысл?

В том и смысл, чтобы не делать так, что обращение можно свернуть в "через две точки". Если сворачивается, значит что-то сделано неправильно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Закон Деметера на практике
От: Mikhail Polykovsky Россия  
Дата: 20.02.07 12:41
Оценка:
MP>>В чем же тогда смысл?
M>В том и смысл, чтобы не делать так, что обращение можно свернуть в "через две точки". Если сворачивается, значит что-то сделано неправильно.

Извини, что-то я недопонял. Ведь любую строку

object.subObject.method()

можно преобразовать в

sub = object.subObject
sub.metod()

и по твоим словам закон Деметера соблюден. А по моему мнению все равно нарушается, просто в скрытой форме.
Re[7]: Закон Деметера на практике
От: GlebZ Россия  
Дата: 20.02.07 15:46
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>Ну хорошо, пусть Фильтр. Покажи мне пожалуйста, как бы ты сделал метод отбора Машин по МаркеКолеса в классе Фильтр. Метод получает на вход массив объектов "Машина".

Это изначально неверная постановка задачи. Потому как реализация по закону Деметры — разделяет функциональность в том числе по методам. И это будет не один метод. Что-то типа следующего:
public class CarsCollectionHelper
{
.....
   public List<Car> FilterByMark(List<Car> source, Mark mark)
   {
        List<Wheel> wheels=GetWheels(source);
        List<Wheel> wheelsMarked=FilterByMark(wheels, mark);
        return GetOwnerCars(wheelsMarked);
   }
   List<Wheel> GetWheels(List<Car> source){...}
   List<Wheel> FilterByMark(List<Wheel> source){...}
   List<Car> GetOwnerCars(List<Wheel> source){...}
}
Re[8]: Закон Деметера на практике
От: Mikhail Polykovsky Россия  
Дата: 20.02.07 19:10
Оценка:
MP>>Ну хорошо, пусть Фильтр. Покажи мне пожалуйста, как бы ты сделал метод отбора Машин по МаркеКолеса в классе Фильтр. Метод получает на вход массив объектов "Машина".
GZ>Это изначально неверная постановка задачи. Потому как реализация по закону Деметры — разделяет функциональность в том числе по методам. И это будет не один метод. Что-то типа следующего:
GZ>
GZ>public class CarsCollectionHelper
GZ>{
GZ>.....
GZ>   public List<Car> FilterByMark(List<Car> source, Mark mark)
GZ>   {
GZ>        List<Wheel> wheels=GetWheels(source);
GZ>        List<Wheel> wheelsMarked=FilterByMark(wheels, mark);
GZ>        return GetOwnerCars(wheelsMarked);
GZ>   }
GZ>   List<Wheel> GetWheels(List<Car> source){...}
GZ>   List<Wheel> FilterByMark(List<Wheel> source){...}
GZ>   List<Car> GetOwnerCars(List<Wheel> source){...}
GZ>}
GZ>


Ага, значит плодить методы, каждый из которых занимается небольшой частью работы. Спасибо, понял.
Re: Закон Деметера на практике
От: Dmitry Dolgopolov  
Дата: 21.02.07 17:36
Оценка: 2 (1)
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>Но мне вот что непонятно. Если мне в метод, например, передается объект "Машина", у которой надо накачать колеса, как лучше поступить?


Есть несколько вариантов, при которых не нарушается упомянутый закон. Если объект класса Машина умеет обрабатывать сообщение накачатьКолесо(), тогда можно рассмотреть такой вариант:
void Персонал::обслужитьМашину(Машина машина)
{
    машина.накачатьКолесо(переднее-левое);
    машина.накачатьКолесо(переднее-правое);
    машина.накачатьКолесо(заднее-левое);
    машина.накачатьКолесо(заднее-правое);
    ...
}

Однако, если колеса в большинстве случаев качаются все вместе, тогда более подходящий вариант следующий:
void Персонал::обслужитьМашину(Машина машина)
{
    машина.накачатьКолеса();
    ...
}

Выбор, наверное, зависит еще и от возможности исключений в каждом из приведенных методов объекта "машина".
Re[2]: Закон Деметера на практике
От: Dmitry Dolgopolov  
Дата: 21.02.07 17:49
Оценка:
DD>void Персонал::обслужитьМашину(Машина машина)
DD>{
DD>    машина.накачатьКолесо(переднее-левое);
DD>    машина.накачатьКолесо(переднее-правое);
DD>    машина.накачатьКолесо(заднее-левое);
DD>    машина.накачатьКолесо(заднее-правое);
DD>    ...
DD>}

Чтобы было более понятно, метод накачатьКолесо() класса Машина:
void Машина::накачатьКолесо(ИдентификаторКолеса колесо)
{
    колеса[колесо].накачать();
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.