我理解PHP中根本不支持multiple inheritance 1 ,虽然存在许多“hacks”或变通方法来模拟它,但我也理解{{3}这样的方法可能比这些变通方法更灵活,更稳定,更易理解。奇怪的是,PHP的5.4 object composition将是合适的解决方案,但我们还没有,我们是不是。
现在,这不仅仅是一个“ amidoinitrite?”问题,但我想确保我的方法对其他人有意义。
鉴于我有课程Action
和Event
(还有更多,但我们会保持简短)并且他们都需要( near >)相同的方法,显而易见的方法是;创建一个共同的基类,扩展和去;毕竟,它们在概念上相似,足以构成一个阶级层次结构中的兄弟姐妹(我认为)
问题是Event
需要扩展一个本身无法扩展的类( Exception
)。方法(和属性)都属于“属性”值,我们称之为“选项”和“数据”,其中“选项”是存储在类级别的值,“数据”是存储在实例级别的值。
除了(没有双关语)Exception
类之外,我可以简单地创建一个所有相关对象扩展的公共类,以便继承必要的功能,但我是想知道我能做些什么来避免Event
中看似不可避免的代码重复;此外,其他在概念上与兄弟姐妹不相似的类需要此功能。
到目前为止,答案似乎是,使用对象组合方法,创建一个Data
类,并在两点进行管理:
Data
实例作为“数据”。initialize()
方法)创建一个Data
实例,静态地将该类用作“选项”。例如,名为IData
和IOption
的接口将由需要此功能的类实现。 IData
只是在使用者身上强制执行Data
类的实例方法,并且调用将转发到实例Data
属性对象,而IOption
将强制执行类似命名的方法( 将“data”替换为“option”),这些方法将转发给静态Data
属性对象。
我正在看的是这样的事情(这些方法在外观上有些天真,但我为了简洁起见,我已经将它们缩小了):
interface IData{
public function setData($name, $value);
public function putData($name, &$variable);
public function getData($name = null);
}
interface IOption{
public static function initializeOptions();
public static function setOption($name, $value);
public static function setOptions(Array $options);
public static function getOptions($name = null);
}
class Data implements IData{
private $_values = array();
public function setData($name, $value){
$this->_values[$name] = $value;
}
public function putData($name, &$variable){
$this->_values[$name] = &$variable;
}
public function getData($name = null){
if(null === $name){
return $this->_values;
}
if(isset($this->_values[$name])){
return $this->_values[$name];
}
return null;
}
}
class Test implements IData, IOption{
private static $_option;
private $_data;
public static function initializeOptions(){
self::$_option = new Data();
}
public static function setOption($name, $value){
self::$_option->setData($name, $value);
}
public static function setOptions(Array $options){
foreach($options as $name => $value){
self::$_option->setData($name, $value);
}
}
public static function getOptions($name = null){
return self::$_option->getOptions($name);
}
public function __construct(){
$this->_data = new Data();
}
public function setData($name, $value){
$this->_data->setData($name, $value);
return $this;
}
public function putData($name, &$variable){
$this->_data->putData($name, $variable);
return $this;
}
public function getData($name = null){
return $this->_data->getData($name);
}
}
那么我从哪里开始呢?我无法摆脱这种感觉,即我正在摆脱优秀的设计;我在客户端类和存储类之间引入了不可逆的依赖关系,接口无法明确强制执行。
修改:或者,我可以将Data
(必要时)的引用保持公开,从而无需代理方法,从而简化了构图。那么问题是,我不能偏离Data
类功能,例如,如果我需要递归地getData()
行动,就像这个片段举例说明的那样:
function getData($name = null){
if(null === $name){
// $parent_object would refer to $this->_parent
// in the Test class, given it had a hierarchal
// implementation
return array_replace($parent_object->getData(), $this->_values);
}
// ...
}
当然,这一切都归结为每个类别的定义,以支持任何偏离默认实现。
我认为最终的结果是,我无法理解代码重复的位置“好”(或更准确,不可避免)以及我可以将常用功能提取到容器中的位置,以及如何跨类引用和使用包含的功能,在必要时偏离(通常可忽略)。同样,特征(我在测试中的粗略测试)似乎是完美的契合,但组合原则早在5.4之前就存在了(和PHP完全就此而言并且我确信有一种“经典”的方法来实现这一目标。
<子> 1.有趣的是,维基百科的traits页面已被标记为进行版权调查。钻石问题似乎是一个合适的替代品。 子>
答案 0 :(得分:1)
编辑:我刚刚再次阅读了您的问题,您似乎在暗示您实际上是在使用getter和setter来操纵数据。如果是这种情况,那么您可以向我提供有关您正在尝试实现的内容的更多详细信息。我怀疑你是如何决定对对象和数据进行建模的,这导致你遇到这种情况,另一种方法可以解决问题。
您不需要多重继承。你甚至不需要你编写的大部分代码。
如果类'Data'和'Option'的目的是简单地存储数据,那么使用数组。或者,如果您更喜欢对象的语法,则将数组转换为对象或stdClass的实例:
$person = (object)array(
'name' => 'Peter',
'gender' => 'Male'
);
OR
$person = new stdClass;
$person->name = 'Peter';
$person->gender = 'Male';
拥有一大堆实际上并没有对数据做任何事情的getter和setter是毫无意义的。