Как я могу гарантировать, что объект принадлежит только одной коллекции, сохраняя принцип СУХОГО?
Я пытаюсь решить проблему в своем PHP-коде, но это также то, что я не смог решить и в другом коде.
У меня есть объект, который должен принадлежать одной и только одной коллекции. И я буду прежде всего получать доступ к этим объектам с точки зрения коллекции. Другой код не сможет найти объект, не пройдя через коллекцию.
Итак, как я справлялся с этим в прошлом, так это чтобы дать объекту ссылку на коллекцию. Таким образом, мы пытаемся удостовериться, что Объект может принадлежать только одной Коллекции. Затем я бы добавил объект в коллекцию.
public function __construct(Collection $c)
{
$this->setCollection($c);
}
public setCollection(Collection $c)
{
$this->collection = $c;
$c->addObject($this);
}
Это очевидное противоречие с "Не повторяй себя". И это происходит потому, что требования, которым нужен легкий доступ к коллекции объектов и что объекты принадлежат только одной коллекции, противоречат друг другу. Объект знает, что он находится в Коллекции, и Коллекция знает, что Объект находится в этой коллекции. Если какой-либо из них не синхронизирован, система сломана.
И проблемы становятся очевидными, когда вы начинаете пытаться создать код для перемещения объекта из одной коллекции в другую. Или при удалении объекта.
Итак, кто-нибудь нашел решение этой проблемы? Есть что-то, что я должен попробовать? В конце я могу заставить его работать с двойной проверкой, но кажется, что должен быть лучший способ.
1 ответ
Я не уверен, что следую вашей логике до конца игры "двойной проверки"... но что не так с таким кодом?
class Collection {
public function AddMember(Member $m) {
$m->SetCollection($this);
// add to underlying data structure
}
public function RemoveMember(Member $m) {
// remove from underlying data structure
}
}
class Member {
private $collection = null;
public function SetCollection(Collection $c) {
if($this->collection)
$this->collection->RemoveMember($this);
$this->collection = $c;
}
public __destruct() {
if($this->collection)
$this->collection->RemoveMember($this);
}
}
Синтаксис, вероятно, отключен, обрабатывайте его как псевдо-код, не тестировали, используйте ссылки там, где это необходимо, другие отказы от ответственности и т. Д.
Это отличный шаблон проектирования, где дружественные классы / методы были бы полезны для правильной инкапсуляции, чтобы не позволить никому, кроме объекта коллекции, установить или удалить элемент из своей коллекции. Вы также захотите долго и усердно подумать о том, какие методы вы хотите использовать в качестве точек входа, и в этих случаях поступайте правильно, не попадая в цикл рекурсии. Для такого класса фреймворка / библиотеки модульные тесты значительно облегчат вашу жизнь.
Да, я могу видеть, где вы можете беспокоиться о необходимости сделать if
проверьте, прежде чем делать что-либо с добавлением, удалением или уничтожением. Но это природа умного и безопасного указателя / эталонного образца. Принцип СУХОЙ заключается не столько в том, чтобы избежать избыточности проверок безопасности, сколько в том, чтобы избежать нескольких копий данных или избыточных реализаций алгоритмов. Да, каждый из этих методов в моем псевдокоде технически является алгоритмом, но вот несколько вещей, которые нужно пережить (хорошо, это действительно одно и то же, заявленное с разных точек зрения):
- Они работают в постоянном времени (при условии, что вы избежите ловушек рекурсии, о которых я упоминал).
- Серьезно: самый короткий алгоритм.
- Если вы беспокоитесь об оптимизации половины вашего
if
операторы в библиотеке, вам не хватает леса для (одного) дерева. Время на оптимизацию тратится на то, чтобы сделать код более простым в использовании, обслуживании и снижении сложности алгоритмов. Он не становится менее сложным, чем алгоритм с постоянным временем. - Вы не собираетесь привязывать свой процессор, делая дополнительные
if
заявление о каждом добавлении или удалении. Вы привязываете свой процессор, запустивO(n^2)
алгоритм по большомуn
,
Подводя итог, можно сказать, что нет лучшего способа реализовать безопасную структуру данных с двойными связями. Вы должны проверить безопасность каждой ссылки, и так оно и будет.