在OOP中处理双向关联的最佳方法

时间:2015-10-15 15:03:24

标签: php oop bidirectional

我想知道在O.O.P中处理双向关联的最佳方法。我在Google和SO 上找到了多个解决方案,但每个解决方案似乎都有缺陷。语言无关紧要,但让我们用PHP来说明我的意思:

假设我有一个简单的国家.. [1..n] ..城市协会:

public class State {
    public $cities;
    public function add_city($city) {}
}
public class City {
    public $state;
    public function set_state($state) {}
}

实施#1:

public class State {
    public $cities;
    public function add_city($city) {
        $this->cities[] = $city;
        $city->state = $this;
    }
}
public class City {
    public $state;
    public function set_state($state) {
        $this->state = $state;
        $state->cities[] = $state;
    }
}

此实现的两个问题是:

  • “$ state”和“$ cities”必须是公开的(所以任何人都可以在不使用公共函数add_city的情况下添加城市...)。没有“朋友 大多数语言中的“概念”。
  • 在添加
  • 之前,公共函数可能必须执行某些操作

实施#2:

public class State {
    public $cities;
    public function add_city($city) {
        $this->cities[] = $city;
        if ($city->state != $this) {
            $city->set_state($this);
        }
    }
}
public class City {
    public $state;
    public function set_state($state) {
        $this->state = $state;
        if (!in_array($this, $state->cities)) {
            $state->add_city($this);
        }
    }
}

比#1好一点但是“set_state”函数必须调用“in_array”,必须使用的语言为O(n)(将快速O(1)操作转换为O(n)操作。)

实施#3:

public class State {
    public $cities;
    public function add_city($city, $call_the_other_function = true) {
        $this->cities[] = $city;
        if ($call_the_other_function) {
            $city->set_state($this, false);
        }
    }
}
public class City {
    public $state;
    public function set_state($state, $call_the_other_function = true) {
        $this->state = $state;
        if ($call_the_other_function) {
            $state->add_city($this, false);
        }
    }
}

实施#3是非常有效的,但由于额外的可选参数,它有点“丑陋”(缺乏更好的术语)

无论如何,如果有人知道“正确的方式”(tm)是什么,我想知道。

编辑: 如果可能的话我想要一个解决方案:

  • 不使用其他课程
  • 不知道创建对象的顺序(即不是“构造函数”解决方案)

2 个答案:

答案 0 :(得分:2)

我尝试使用构造函数,这样,当您实例化城市时,您可以直接传递其状态。

public class State {
    private $cities;
    public function add_city($city) {
        $this->cities[] = $city;
    }
}

public class City {
    private $state;
    function __construct($state) {
        $state->add_city($this)
        $this->state=$state
    }
}

答案 1 :(得分:0)

在所有提案中,City都知道State中的方法,反之亦然。如果您引入了负责将城市与州(例如LocationService)与linkCityToState等一种方法相关联的第三类,该怎么办?有了这个,您可以稍后使用linkCityToCountry或某些高级逻辑(例如getPostalCodeFromApi)对其进行扩展。

如果您担心性能问题,请将列表转换为hashset,这会将查找复杂性降低到O(log n)

同样在您的实施#1中,您有city->cities ...?

在任何情况下,除非我编写压缩算法,驱动程序,海量数据库查询等,否则我永远不会使用解决方案#3。