Рекомендации ООП, когда один объект нуждается в изменении другого - PullRequest
1 голос
/ 08 октября 2009

(это среда, похожая на C) Скажем, у меня есть два экземпляра объекта, автомобиль и bodyShop. Автомобиль имеет цветной iVar и соответствующие аксессуары. В bodyShop есть метод с именем «paintCar», который принимает объект автомобиля и меняет его цвет.

Что касается реализации, то для того, чтобы bodyShop действительно мог изменять цвет объекта автомобиля, я вижу два способа сделать это.

  1. Используйте оператор «&» для передачи указателя на автомобиль. Затем bodyShop может либо сказать машине, чтобы она выполняла какой-либо метод, чтобы он изменил цвет, либо он может напрямую использовать принадлежность автомобиля.

  2. Передайте объект car по значению, сделайте то же самое, чтобы изменить цвет, затем попросите метод вернуть объект car с новым цветом. Затем назначьте оригинальный автомобильный объект новому автомобильному объекту.

Вариант 1 кажется мне более простым, но мне интересно, соответствует ли он лучшим методикам ООП. В общем случае для «максимального ООП» оператор «&» хорош или плох? Или, может быть, я полностью упускаю лучший вариант, который сделал бы этот супер OOPer. Посоветуйте пожалуйста :)

Ответы [ 8 ]

5 голосов
/ 09 октября 2009

Вариант 1 предпочтителен:

BodyShop может либо рассказать машине выполнить какой-то метод, который он должен изменить цвет, или он может использовать автомобиль средства доступа напрямую.

Еще лучше ... создать интерфейс IPaintable. У Автомобиля реализовать IPaintable. Пусть BodyShop зависит от IPaintable вместо Car. Преимущества этого:

  • Теперь BodyShop может рисовать все, что реализует IPaintable (автомобили, лодки, самолеты, скутеры)
  • BodyShop больше не тесно связан с автомобилем.
  • BodyShop имеет более тестируемый дизайн.
3 голосов
/ 08 октября 2009

Я бы предположил, что обязанность bodyShop состоит в том, чтобы модифицировать автомобильные объекты, поэтому # 1 кажется правильным способом для меня. Я никогда не использовал язык, где необходим оператор "&". Обычно мой объект bodyShop будет вызывать car.setColor (newColor), и это будет так. Таким образом, вам не нужно беспокоиться об остальных атрибутах оригинального автомобиля, включая проблемы с сохранением - вы просто оставляете их в покое.

2 голосов
/ 08 октября 2009

Так как вас интересует лучшая практика ООП, вы должны игнорировать снижение производительности, которое вы получаете с опцией 2. Единственное, что вас должно заинтересовать, это сделать любую опцию, излишне увеличивающую связь между двумя классами, нарушена ли инкапсуляция и сохраняется личность.

Учитывая это, вариант 2 менее желателен, так как вы не можете определить, какие другие объекты содержат ссылки на исходный автомобиль или, что еще хуже, содержат автомобиль. Короче говоря, вы нарушаете ограничение идентичности, поскольку два объекта в системе могут иметь разные представления о состоянии автомобиля. Вы рискуете сделать всю систему несовместимой.

Конечно, ваша конкретная среда может этого избежать, но, безусловно, было бы лучше избегать этого.

Последний пункт, имеет ли ваш объект bodyShop состояние; поведение и личность? Я понимаю, что вы объяснили только необходимый минимум, но, возможно, bodyShop на самом деле не является объектом.


Функциональный v OO приближается

Интересно отметить, что вариант 2 будет близок к подходу в среде функционального программирования - поскольку изменения состояния не допускаются, единственным подходом будет создание нового автомобиля, если его цвет изменился. Это не совсем то, что вы предлагаете, но это близко.

Это может звучать как полное излишество, но оно имеет некоторые интересные последствия для доказательства правильности кода и параллелизма.

1 голос
/ 08 октября 2009

Я не уверен, что означает эта "C-подобная среда". В C вам нужно это:

int paintCar(const bodyShop_t *bs, car_t *car);

где вы изменяете содержимое, указанное автомобилем. Для большой структуры в C вы всегда должны передавать указатель, а не значение в функцию. Итак, используйте решение 1 (если под «&» вы подразумеваете оператор C).

1 голос
/ 08 октября 2009

Вариант 1 выигрывает для меня. Оператор & неявен во многих языках OO (таких как Java, Python и т. Д.). В этих языках часто не используется «передача по значению» - таким образом передаются только примитивные типы.

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

0 голосов
/ 08 октября 2009

В дополнение к другим вариантам, опция 1 позволяет методу paintCar возвращать код завершения, который указывает, успешно ли автомобиль изменил цвет или были проблемы с ним

0 голосов
/ 08 октября 2009

Зависит от того, может ли метод кузовного цеха выйти из строя и оставить машину в неопределенном состоянии. В этом случае вам лучше работать с копией автомобиля или копией всех соответствующих атрибутов автомобиля. Затем, только когда операция прошла успешно, вы копируете эти значения в машину. Таким образом, вы заканчиваете тем, что присваиваете новый автомобиль старому в рамках метода кузовного цеха. Правильное выполнение этого необходимо для обеспечения безопасности исключений в C ++, и может получить nasty .

Также возможно и иногда желательно использовать другой шаблон - возврат нового объекта при модификации. Это полезно для интерактивных систем, требующих отмены / повтора, поиска в обратном направлении и для всего, что связано с моделированием эволюции системы объектов со временем.

0 голосов
/ 08 октября 2009

Я тоже согласен с первым 1. Я не могу сказать, что это лучшая практика, потому что я никогда не могу точно понять, что такое лучшая практика в умах других людей ... Я могу сказать вам, что лучшая практика в моем уме - это самая простой метод, который работает для работы. Я также видел этот подход, принятый в API-интерфейсе winspell win и других c-ish api, которые мне приходилось использовать. Так что да, я согласен со Скоттом.

http://hunspell.sourceforge.net/

// на всякий случай, если вы заинтересованы в поиске кода других людей

...