Наследование vs Агрегация

Long

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

zerkms

TDD infected
Команда форума
предлагаю сойтись на том, что имеют право на жизнь оба подхода - в каждом есть свои плюсы и минусы.
хехе. с точки зрения "рабочести" - да, оба варианта удовлетворяют требованиям: код работает.
с точки зрения логики - без дополнительной защиты твой код становится хрупким за счёт возможности бесконтрольного прямого доступа к данным. твой вариант защиты, на сколько я понял, состоит в переопределении методов акцессоров как-то так:

PHP:
public function set(...)
{
throw new Exception('You should use concrete setter instead');
}
т.о. - весь смысл наследования вообще теряется - потому что от предка в наследнике не остаётся ничего.
 

Long

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

zerkms

TDD infected
Команда форума
упихать в более-менее разумное количество строк как можно больше всяческих паттернов и оо подходов.
ооооо, господа, с этого и нужно было начинать!!!
предлагаю сюда паттерн Strategy, потому что он клёвый, и один из Memento/State - потому что они тоже клёвые, но на деле я никогда их не применял :-(

а по поводу собеседования - я вероятно бы покрутил пальцем у виска. пальцем проводящего собеседование у виска проводящего собеседование %)
 

Long

Новичок
zerkms, можно обойтись без исключений, назвать метод register, а не addMarker :) или более униваерсально - поменять его название в обоих классах на add ;)
 

zerkms

TDD infected
Команда форума
да, но это заставляет меня знать слишком много о том, какие хранилища могут быть в системе.
класс - "серверная часть". процесс использования и конфигурирования класса - "клиентская".

клиентский код обязан знать, что и как есть в системе.

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

$foobar = new concreteRegistry('storageDSN');

-~{}~ 10.02.09 12:10:

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

Long

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

предлагаю сюда паттерн Strategy, потому что он клёвый, и один из Memento/State
возможно допишу :) но эти, почти 660 строк, писались за пару часов около 4х утра, поэтому на подобные садисткие методы меня уже не хватило :D

зачем мне менять TheRegistry на TheMemcachedRegistry? в данной системе совершенно не предполагается наличие 2х и более хранилищ. поэтому смена реализации проходит просто и безболезненно в рамках TheRegistry. еща раз повторюсь - в данном конкретном случае "клиент" не обязан знать о том, как устроено хранилище.
 

zerkms

TDD infected
Команда форума
в приват закинь задание, стало жутко интересно? :)
 

Wicked

Новичок
Long
можно обойтись без исключений, назвать метод register, а не addMarker или более униваерсально - поменять его название в обоих классах на add
Уже не важно. Оба подхода нарушают принцип подстановки Лисковой :)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Я поддерживаю Лонга.
1. Он мне более симпатичен как человек. :)
2. В реальной жизни его подход более правильный, чем "теоретическая грамотность" апологетов паттернизации, которые в жизни пишут абы как чтобы успеть.
 

HraKK

Мудак
Команда форума
Шикарно. Только боюсь, у нас нету приза зрительских симпатий :(
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Да, я в подобных ситуациях обычно пишу наследование.
Если вдруг появляется необходимость, можно переписать на аггрегацию/делегирование какое-нибудь.

-~{}~ 10.02.09 11:36:

Реально, аргумент "а если я подставлю некорректные данные" - бред, классическая защита программиста от самого себя.
Напиши `rm -rf *` и докажи, что safe mode необходим! :)

-~{}~ 10.02.09 11:41:

Автор оригинала: HraKK
Шикарно. Только боюсь, у нас нету приза зрительских симпатий :(
Был вопрос "кто прав". Прав Лонг с фразой "имеют место оба варианта", я против коллективного закидывания камнями грешницы за абстрактное несоответствие идеалу этого коллектива.
 

AmdY

Пью пиво
Команда форума
Автор оригинала: Long
zerkms, можно обойтись без исключений, назвать метод register, а не addMarker :) или более униваерсально - поменять его название в обоих классах на add ;)
вот оно. нужно было в cMarkersBox унаследовать интерфейс TheRegistry_Interface, если так хочется связать с TheRegistry, а метод addMarker тогда назвать register. И разработчики бы знали, что cMarkersBox является регистром для cMarker и работали бы с ним как с TheRegistry не клезая в код самого cMarkersBox
public function register(cMarker $m) {
TheRegistry::getInstance()->register( $m->getColor(), $m );
Log::add('Добавили маркер цвета ' . $m->getColor() . ' и типа ' . $m->getType());
}
 

HraKK

Мудак
Команда форума
AmdY
Все равно бред. Мы не сможем унаследовать интерфейс бекауз register(cMarker $m) будет нарушением интерфейса.

-~{}~ 10.02.09 12:38:

Был вопрос "кто прав".
В абсткрактном коде призванным быть Правильным с большой буквы. В программе я и сам похуже ошибки допускаю из-за того что не подумаю\не предусмотрю\не хватает времени\лень. Но тут мы не говорим "можно ли" мы говорим что ПРАВИЛЬНО, а что нет. Можно то, оно можно. Но не правильно.
 

AmdY

Пью пиво
Команда форума
HraKK
действительно, нужно instanceof вместо типхинтинга.
просто если cMarkersBox должен вести себя как TheRegistry, то интерфейс не помешает. не знаю как это с фаулеро-бучевской точки зрения, но для разработчика проще.
 

HraKK

Мудак
Команда форума
Как только мы заменим на instanceof и будем использовать
TheRegistry::getInstance()
вместо $this->
наш cMarkersBox превращается в класс который только проксирует данные в класс TheRegistry, и таким образом мы передатчику (человеку) наследуем хранилище ( холодильник).
 

AmdY

Пью пиво
Команда форума
я бы сказал, мы получим человека, которому объяснили, что молоко нужно ставить в холодильник, но нельзя совать в морозильную камеру.
 

HraKK

Мудак
Команда форума
Это все равно не оправдывает наследование холодильника - то есть запихивание человека внутрь холодильника, и он внутри распихует по полкам, и не может конечно до морозильной камеры добраться. А вот
человека, которому объяснили, что молоко нужно ставить в холодильник, но нельзя совать в морозильную камеру.
быыло бы правильным решением.
 
Сверху