如何确保一个对象只属于一个集合,同时保持DRY原则?


How can I ensure that an object only belongs to one collection, while maintaining the DRY principle?

我正试图解决我的PHP代码中的问题,但这也是我在其他代码中无法解决的问题

我有一个对象,它必须属于且只能属于一个集合。我将主要从藏品的角度来访问这些物品。如果不遍历Collection,其他代码就不能找到Object。

所以,我过去处理这个问题的方式是给对象一个对集合的引用。通过这种方式,我们尝试满足对象只能属于一个集合。然后我将对象添加到集合中。

public function __construct(Collection $c)
{
    $this->setCollection($c);
}
public setCollection(Collection $c)
{
    $this->collection = $c;
    $c->addObject($this);
}

这显然与"Don't Repeat Yourself"相矛盾。这是因为需要方便地访问对象集合和要求对象只属于一个集合的需求是不一致的。对象知道它在集合中集合也知道对象在集合中。如果其中一个不同步,系统就会崩溃。

当您开始尝试编写代码将对象从一个集合移动到另一个集合时,问题就变得明显了。或在删除对象时。

那么,有人找到解决这种问题的方法了吗?有什么我应该试试的吗?最后,我可以通过大量的双重检查使其工作,但似乎必须有一个更好的方法。

我不确定我是否遵循你的推理路线,直到"双重检查"的最后游戏…但是这样的代码有什么问题呢?

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检查。但这就是聪明的人的本质。安全指针/引用模式。DRY原则与其说是为了避免冗余的安全检查,不如说是为了避免数据的多个副本或算法的冗余实现。是的,我的伪代码中的每个方法在技术上都是一个算法,但这里有一些事情需要仔细考虑(好吧,它们实际上是一样的东西,从不同的角度陈述):

  1. 它们在恒定时间内运行(前提是您避免了我提到的递归陷阱)。
  2. 严重:最短的算法。
  3. 如果您担心在库中优化出一半的if语句,那么您就错过了(单个)树的森林。优化时间最好花在使代码更易于使用、更易于维护和降低算法的复杂性上。它不会比常数时间算法更简单。
  4. 你不会通过在每次添加或删除上做额外的if语句来固定你的处理器。通过在大型n上运行O(n^2)算法来固定处理器。
总而言之,没有更好的方法来实现一个安全的、双链接的数据结构。你必须检查每一个链接的安全性,这就是它的方式。