Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 在OOP中处理双向关联的最佳方法_Php_Oop_Bidirectional - Fatal编程技术网

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

Php 在OOP中处理双向关联的最佳方法,php,oop,bidirectional,Php,Oop,Bidirectional,我想知道在O.O.p.中处理双向关联的最佳方法。我在Google上找到了多个解决方案,因此,,但每一个解决方案似乎都有缺点。语言是不相关的,但让我们用PHP来说明我的意思: 假设我有一个简单的州……城市协会: public class State { public $cities; public function add_city($city) {} } public class City { public $state; public function set_

我想知道在O.O.p.中处理双向关联的最佳方法。我在Google上找到了多个解决方案,因此,,但每一个解决方案似乎都有缺点。语言是不相关的,但让我们用PHP来说明我的意思:

假设我有一个简单的州……城市协会:

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;
    }
}
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);
        }
    }
}
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);
        }
    }
}
这一实施的两个问题是:

  • “$state”和“$cities”必须是公共的(因此任何人都可以在不使用公共函数add_city…)的情况下添加城市)。没有“朋友” 大多数语言中的“类”概念
  • 在添加之前,公共函数可能需要执行一些操作
实施#2:

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;
    }
}
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);
        }
    }
}
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);
        }
    }
}
比#1稍微好一点,但“set_state”函数必须调用“in_array”,在must语言中,它是O(n)(将快速O(1)操作转换为O(n)操作)

实施#3:

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;
    }
}
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);
        }
    }
}
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),我想知道

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

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

在您的所有提案中,City都知道州内的方法,反之亦然。如果您引入了负责将城市链接到州的第三类,例如
LocationService
,使用一种方法,例如
linkcitystate
,该怎么办?有了它,您以后可以使用
linkCityToCountry
或一些高级逻辑(如
getPostalCodeFromApi
)对其进行扩展

如果您担心性能,请将列表转换为hashset,这将把查找复杂性降低到仅仅
O(logn)

同样在您的实现中#1您有
city->cities


在任何情况下,我都不会选择解决方案3,除非我正在编写压缩算法、驱动程序、大规模数据库查询等。

我会尝试使用构造函数,这样,当你建立一个城市时,你可以直接传递它的状态

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
    }
}

“Right Way(tm)”问题与Stackoverflow无关,因为它们倾向于生成基于意见的答案。请回顾一下,看看你应该问什么,不应该问什么。请原谅,我对你的第一个实现感到困惑。为什么这些变量需要公开?“friend”类可以只在另一个类上使用public方法,不是吗?除了@TimLewis所说的,也许你的问题更适合:)是的,但是“局外人”可以直接从集合中访问“add”函数,即$my_state->get_cities()->add()(绕过$my_state->add_city()“附加代码”…)我相信没有正确的方法或完美的代码。要么是对你有用,要么不是。如果它没有,它就有资格重构,故事结束了;我应该在我的问题中添加“不使用任何附加类”。好吧,循环引用通常通过引入第三类来解决。诚实的问题:为什么你永远不会使用解决方案#3?你浏览随机代码。您将看到一个方法:
add\u city()
。它接受
城市
。完美的但是它有一个
bool
参数=WTF1。然后您会看到它的名称:
调用其他函数
=WTF2。。。这打破了几个模式-KISS、SRP,是过早优化的一个例子。如果你真的需要那么多的性能,不要使用PHP。但是这就是为什么这个参数是可选的,默认情况下是真的,所以你不必在原始调用中包含它。。。无论如何,感谢您所做的一切。如果在创建城市时该州还不存在(稍后将创建并链接),该怎么办?您需要指定您的用例,然后代码就会出现。城市和州之间存在依赖关系:一个城市只属于一个州,一个州包含零个或多个城市。此依赖项要求在其所属州之后创建城市。答案用代码表达了这种说法;它还提供了正确的属性封装