我有一个场景,我有几个类从一个共同的祖先扩展,因为它们都共享共同的属性和方法。这些类中的一半(组A)包含另一半(组B)不共享的属性,因此组A中的每个类都显式声明此属性而不是父类。
e.g。
class parent
{
}
class child1 <and child2, and child3> extends parent
{
protected $specialProperty;
}
class child4 <and child5, and child5> extends parent
{
// no "$specialProperty"
}
我需要实施一些行为,以$specialProperty
为准。当然,我想将它放在父类中并且只执行一次,但是$specialProperty
并不存在于所有子类中。
一个选项是创建一个声明$specialProperty
并实现所需行为的中间抽象类,但由于以下几个原因,我不愿意这样做:
parent
以上5级。我是否真的应该创建越来越多的图层来弥补一个不太理想的类层次结构,这个层次结构是在需求有限的情况下构思出来的?另一个选择是执行以下操作:
class parent
{
public function functionThatTheAppWillCallAutomatically()
{
if ( property_exists($this, 'specialProperty') )
{
// do stuff with specialProperty
}
}
}
“stuff”将由具有$specialProperty
的子类执行,并由不具有class archivalDecorator extends decoratorBase /* decoratorBase just has constructor and the object property */
{
public function archive()
{
if ( !$this->object->archive() )
{
return false;
}
if ( property_exists($this->object, 'specialProperty') )
{
// do extra stuff here that involves "specialProperty"
}
return true;
}
}
的子类执行。我 讨厌 这个解决方案,因为它对我来说似乎是错误和草率的。在我看来,父母不应该根据孩子的属性来决定做什么(哎呀,它可能甚至不知道孩子存在 - 这不是第一个孩子上课的原因?)
简而言之,我不确定这两个选项中哪一个最不好,或者是否有更好的可能性。我焦急地等待着建议。
谢谢!
修改
我最终执行以下操作来实现此专用功能。
property_exists(...)
这样,我的所有对象都执行相同的归档工作流,但是需要特殊行为的类仍然可以执行它,而不需要在层次结构中为这些特殊情况实现数十个子类。
虽然我仍然使用$specialProperty
来确定是否需要特殊行为,但我认为现在这样做是可以的,因为我没有在父类中执行此操作。 $this
是一个公共属性,因此没有理由外部类不应该知道它,但是父类使用{{1}}检查子类中的属性是错误的。
我希望我没有误用这个概念。
答案 0 :(得分:1)
很难说不知道你的课程在做什么,但你的问题(具有多个子树的深层次结构,可选的交叉树功能等)表明需要一些decorator pattern。
答案 1 :(得分:1)
我不太熟悉PHP,并且没有任何类层次结构的细节,但我想评论您对类层次结构深度的担忧。
如果您建模的任何内容在其属性方面都是异质的,那么您最终会得到一个深层次的层次结构,那么放置一个假设并且说“五个级别可以但不是六个”或“x”是没有意义的许多中间人太多了“。除非你可以抽象某些差异并且根本不代表它们,因此将多个实例放在相同的“等价类”中,你必须在某处对模型进行建模,这可能与任何一样好。如果不在类型层次结构中执行此操作,则最终可能会使用类型检查或其他属性。
如果您发现自己的层次结构太复杂,因为某些属性的存在重叠,您可能希望查看多重继承(或多个接口实现),如装饰器模式,如果在PHP中方便支持。
答案 2 :(得分:0)
好的,所以你有一个只存在于某个类中的特殊属性,你有一个方法必须对这个特殊属性起作用,但你不知道把它放在哪里?
在课堂上你定义特殊属性怎么样?
class child1 <and child2, and child3> extends parent
{
protected $specialProperty;
public function doSomethingWithSpecialProperty() {
}
}
另一种选择是覆盖父方法:
class child1 <and child2, and child3> extends parent
{
protected $specialProperty;
public function functionThatTheAppWillCallAutomatically() {
parent::functionThatTheAppWillCallAutomatically();
// do other stuff
}
}
您还可以创建一个空方法,以某种方式作为占位符,并在必要时在子类中实现它:
class parent
{
public function functionThatTheAppWillCallAutomatically()
{
$this->extraStuff();
}
protected function extraStuff(){};
}
class child1 <and child2, and child3> extends parent
{
protected $specialProperty;
protected function extraStuff() {
echo $specialProperty,
}
}
否则你可能不得不再考虑一下你的设计。