我有两个类,它们是好朋友,每个类都有另一个需要使用的方法。我不想只公开这些方法,这是目前为止我所能做的。
我认为这是protected
的全部目的,但它只将方法暴露给父类或子类——我的两个类只是好朋友,是一个正直的团队。
为什么这些类是如此长久的伙伴?
嗯,你看,我有一个Item
班和一个Selection
班。项目有一个字符串标签。选择是一组项目,但是,并不是所有的项目都必须在一个选择中(项目可以是独立的)。选择扩展了ArrayObject,这样它就可以在内部存储项目,就像一个很酷的关联数组($selection["label"]
容易访问项目)。
当你改变一个项目对象的label
时,选择关联数组的键需要更新以匹配!
所以,当一个项目被添加到一个选择,选择对象调用该项目的associate
方法,它告诉项目它的爸爸是谁。
然后,每当Item的标签被更改时,Item调用其关联父选择对象的updateKey
方法。
这样,项目、它们的标签和它们所处的选区就能和平共处了:)
无论如何,问题是我的解决方案似乎要求这两个宝贵的方法,associate
和updateKey
,向公众公开。
我编写了下面的演示代码,来解释我的小Item-Selection团队。
<?php
class Item {
private $label;
private $selection;
function __construct ($label) {
$this->label($label);
}
function label ($label=null) {
if (!$label) return $this->label;
if ($this->selection) $this->selection->updateKey($this->label, $label);
$this->label = $label;
return $this;
}
public function associate ($selection=null) {
$this->selection = $selection;
return $this;
}
}
class Selection extends ArrayObject {
public function updateKey ($old, $new) {
$this[$new] = $this[$old];
unset($this[$old]);
return $this;
}
function add () {
foreach (func_get_args() as $argi => $arg) {
if ($arg instanceof Item) $this[$arg->label()] = $arg->associate($this);
else throw new Exception("invalid type for selection->add");
}
return $this;
}
function item ($label) {
return $this->add( new Item($label) );
}
}
$selection = (new Selection)
->item("A")
->item("B");
$selection->add( new Item("C") );
$selection["A"]->label("APPLE");
$selection["B"]->label("BANANA");
$selection["C"]->label("CRANBERRY");
echo "<pre>";
print_r($selection);
echo "</pre>";
?>
如何阻止associate
和updateKey
向公众曝光?
首先,我试着看看是否有一种方法可以让这两个类从一个更大的类继承,希望这可能会使它们足够相关以共享受保护的方法——然而,选择已经扩展了ArrayObject, PHP不允许多重继承。我们能做什么呢?
我应该如何重构它?
我做错了吗?
因为你不能真正使这些方法只对彼此可用,你能做的是使updateKey更像一个事件,像onLabelChange($label)。这样你就不会通过保存:
来暴露选择的实现"嘿,选择,更新你的键,因为我改变了一个标签",
这种方法更像是:
"嘿,选择,我更新了一个标签,所以,做你的业务,无论它是什么"。
在这种情况下,你需要做更多的检查,以确保$label是包含在选择的对象
EDIT:我刚刚发现了PHP 5.4中引入的trait,我不太了解它们(我只是在php.net上读到它们),但它们可能会解决你的困境。
PHP不像c++那样有友谊关系的概念,所以没有。但是,确实没有理由需要隐藏我可以看到的这些方法。事实上,它们似乎是为公众设计的。也许你需要做的是保护这些方法,并确保它们在被其他东西操纵时保持一致。
- 由于"项目可以是独立的",你可能希望
Items
能够与Selections
相关联和重新关联,所以associate()
应该是公共的。 - 在
updateKey()
中添加检查,以确保正在更新的项目是Item的实例,并且是给定选择的成员。 你需要disassociate()方法。还要添加一个成员资格测试。确保项目在通过公共接口操作时适当地解除关联。
如果你的问题只是"如何在PHP中实现友谊",请参阅是否有一个简单的方法来模拟PHP 5.3中的友谊。一般情况下,你可以修改它,但通常不值得。