考虑这个假设情景:
我有一个Stomach
类,它具有contents
属性,应该为其分配类Food
的对象。一种方法是使用一种定位器,例如, setContents($food)
。
但我们假设我们直接分配食物,如$stomach->contents = $orange
。
假设每当Food
对象分配给contents
时,我们需要将对象的eaten
属性更改为true
。有没有办法在不使用被分配的对象的方法(在这种情况下,$stomach
的setter)的情况下这样做?
基本上,我的问题是:我们可以在将对象作为属性分配给另一个对象时调用方法吗?另外,即使有可能,它是不是很糟糕的设计?对不起,如果这是一个愚蠢的问题,所有这些对我来说都是新的。
答案 0 :(得分:5)
这里最好的OOP解决方案是创建一个指示操作的方法,例如eat()
。
为了确保正确的对象 eaten ,您可以定义Interface(Say Food )。该接口可以定义方法setEaten()。胃(虽然我更喜欢哺乳动物或类似的东西,实际上可以吃)然后可以调用setEaten()。
由于它在评论中引起了一些争议,我想指出一个对象定义应该尽可能地反映它实际上做了什么。要减少对象耦合,最好避免直接访问其他类的对象属性,但是当它有意义时使用setter而不是动作没有任何问题(注意我在定义中使用了一个) Food ),它通常取决于开发人员的观点。
然而,这里有道理。考虑一下“猴子吃香蕉”的情况(为了简单起见,请允许我用空气来实现香蕉)。
$m = new Monkey();
$m->eat(new Banana());
完美。现在让我们尝试一下setter。
$m->setContents(new Banana());
现在我们遇到了一个问题,猴子已经包含很多东西,比如骨头,血液,肌肉和大脑等等。所以setContents在这里毫无意义。您可以尝试$m->getStomach()->setContents(new Banana())
但这只会增加对象耦合。
答案 1 :(得分:2)
我同意@dualed关于eat
方法。这就是说实现此方法以使所有属性成为私有/受保护的方式,然后使用__get
/ __set
代理setter。
class Stomach {
protected $contents;
public function setContents(Food $food) {
$this->contents = $food;
$food->eaten = true;
}
public function __set($name, $value) {
$method = array($this, 'set' . $name);
if(is_callable($method)) {
return call_user_func_array($method, array($value));
}
}
public function __get($name) {
$method = array($this, 'get'.$name);
if(is_callable($method)) {
return call_user_func($method);
}
}
}
你会注意到我使用is_callable
而不是method_exists
,因为如果你正在使用虚拟方法处理某些复杂问题,is_callable
应该考虑到这些,而method_exists
依赖于方法在类层次结构中定义。
答案 2 :(得分:1)
__set功能会在这里帮到你。但请确保您没有在类中定义的任何名为contents
的属性。这样做
class Stomach{
private $props = array();
public __set($prop, $value){
if($prop === 'contents' and $value instanceof Food){
$this->prop[$prop] = $value;
}
}
}