2010-03-02 67 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的方法確實會創建某種中間類,或者,正如我所說,重新考慮你的設計。 –