2010-03-02 29 views
1

我有一个场景,我有几个类从一个共同的祖先延伸出来,因为它们都共享共同的属性和方法。这些类中的一半(组A)包含一个不由另一半(组B)共享的属性,因此组A中的每个类显式声明此属性而不是父类。具有不合作类级别的多态性

例如

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并实现所需的行为中间,抽象类,但我不愿意这样做有几个原因:

  1. 此方案将是即将到来更快。那我该怎么做?为每个功能创建5或6个不同的中间人抽象类?
  2. 该类的层次结构已经比parent高5层左右。我是否真的应该创造越来越多的层面来弥补那些构思不够理想的阶级层次结构,而这种层次结构是以有限的需求来构思的?
  3. 至少就PHP而言,不会有那么多的继承层最终导致性能问题?

另一种方法是做到以下几点:

class parent 
{ 
    public function functionThatTheAppWillCallAutomatically() 
    { 
     if (property_exists($this, 'specialProperty')) 
     { 
      // do stuff with specialProperty 
     } 
    } 
} 

的“东西”会由有$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

确实很难说不知道你的类正在做什么,但是你的问题(具有多个子树的深层类层次结构,可选的跨树功能等)表明需要某些decorator pattern

+0

如果我使用装饰器,我仍然需要应用装饰器的代码来检查对象是否需要装饰。也就是说,如果它具有“$ specialProperty”,那么我需要应用装饰器并调用专门的方法,否则我会正常进行。 所以,我在技术上仍然需要有一些逻辑来研究子类,但是这里的区别是我在外部而不是从父类进行。 我想这是什么使它在结构上听起来很健康。它是否正确? –

+0

这不是装饰模式的工作原理。如果你走了这条路线,你会重做你的整个班级树。 –

+0

@Peter Bailey:你能更具体地说我错了吗?我应该用调用decorator来替换对“functionThatTheAppWillCallAutomatically()”的调用(仅当“$ specialProperty”存在时),并让修饰器根据是否声明“$ specialProperty”决定如何执行操作在对象中?或者我完全离开这里? –

1

我对PHP不太熟悉,没有任何关于类层次结构的细节,但我想评论一下你对类层次结构深度的关注。

如果你所建模的模型在其属性方面有足够的异质性,那么你最终会得到一个深层的类层次结构,那么就没有意义放置一个人造的帽子并且说“五个级别都可以,但不是六个”,或者“许多中间商太多了“。除非你可以抽象出某些差异,并且根本不表示它们,因此将多个实例放入相同的“等价类”中,你必须在某个地方对分割进行建模,这可能与任何其他实例一样好。如果不在类型层次结构中执行,则最终可能会有类型检查或额外属性。如果您发现自己的层次结构太复杂,因为某些属性的存在重叠,您可能希望查看多个继承(或多个接口实现),如装饰器模式(如果在PHP中支持该方法)。

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

否则,您可能需要再次考虑您的设计。

+0

这个属性没有在一个类中声明,我有7个类声明了这个属性,7个类声明了这个属性不是,但它们都是从同一个父类继承而来的,我不想将同样的方法复制并粘贴到7个类中。 –

+0

@Mike:那么最类似OOP的方法确实会创建某种中间类,或者,正如我所说,重新考虑你的设计。 –