【问题标题】:How can I ensure that an object only belongs to one collection, while maintaining the DRY principle?如何确保一个对象只属于一个集合,同时保持 DRY 原则?
【发布时间】:2013-05-02 20:41:06
【问题描述】:

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

我有一个必须属于一个且仅属于一个集合的对象。我将主要从集合的角度访问这些对象。如果不通过集合,其他代码将无法找到对象。

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

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

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

这与“不要重复自己”明显矛盾。之所以出现,是因为需要轻松访问对象集合和要求对象只属于一个集合的要求相互矛盾。对象知道它在集合中,集合知道对象在集合中。如果其中任何一个不同步,系统就会损坏。

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

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

【问题讨论】:

    标签: php design-patterns collections


    【解决方案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 语句来固定您的处理器。您可以通过在大型 n 上运行 O(n^2) 算法来锁定您的处理器。

    总而言之,没有更好的方法来实现安全的双向链接数据结构。你必须检查每个链接的安全性,这就是它的方式。

    【讨论】:

    • ifs 来自于访问集合中的成员。想象一个$collection->getMembers() 和遍历其所有成员if($member->getCollection != $this) //prune member 的函数。我已经考虑了您在此处所拥有的内容与观察者模式的组合,因此 Collection 监视成员的更改并在更改时自行修剪。最好将我的担忧表述为“增加复杂性,导致更多麻烦。”
    • 另外,PHP 中没有 friend 可见性。所以我需要进行手动检查以确保有人没有做错什么。不能依靠系统来防止他们破坏东西。
    • 我认为您不需要检查访问权限。如果您正确控制成员和集合对象的添加和删除方法,那么您可以确保集合始终处于良好状态。至于手动检查,我同意这些类需要对修改进行检查,但你真的不需要过火。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 2013-12-22
    相关资源
    最近更新 更多