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

时间:2013-05-02 20:41:06

标签: php design-patterns collections

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

我有一个必须属于一个且只有一个集合的对象。我将主要从集合的角度访问这些对象。其他代码不会在没有通过Collection的情况下找到Object。

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

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

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

这与“不要重复自己”有明显的矛盾。并且因为需要轻松访问对象集合并且要求对象仅属于一个集合的要求彼此不一致。 Object知道它在Collection中,而Collection知道Object在其中是集合。如果两者不同步,系统就会崩溃。

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

那么,有没有人找到解决这类问题的方法呢?有什么我应该尝试的吗?最后,我可以通过大量的双重检查来实现它,但似乎必须有更好的方法。

1 个答案:

答案 0 :(得分: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检查。但这就是智能和智能的本质。安全指针/参考模式。 DRY原则并不是为了避免安全检查的冗余,因为它避免了多个数据副本或算法的冗余实现。是的,我的伪代码中的每个方法在技术上都是一种算法,但是这里有一些可以咀嚼的东西(好吧,它们真的是相同的东西,从不同的角度说明):

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