2012-01-12 43 views
2

我有一個應用程序,其中一些對象都在擴展一個抽象類,它定義的方法如create()edit()retrieve()delete()。由於每個子類對這些函數都使用相同的邏輯,所以抽象類定義了默認行爲,並且在少數情況下需要擴展它們,子類可以覆蓋或使用我內置的鉤子。預防/限制方法繼承

現在我遇到了一些子類需要不可變的情況,這意味着它們不應該有edit()delete()方法。這對我來說聽起來像是一個名爲類似immutable的界面的工作,其中不可變類可以實現。問題在於接口不會阻止方法被調用,它們只是強制執行方法的存在。所以這顯然不會起作用。

製作兩個父類,一個用於可變對象,另一個用於不可變對象,這很醜陋,並且可能會要求維護的問題。我可以讓不可變的對象用一個沒有任何作用的空方法覆蓋違規方法,但是這看起來也很麻煩,就像我沒有在那個時候做適當的OOP一樣。

那麼你會提出什麼樣的建議,作爲允許大量類的所有類都繼承一組方法的最佳方法,但是對於其中的一些方法來說,它們不能繼承所有方法? (有問題的應用程序是用PHP編寫的,但來自任何語言的通用OOP技術仍然可以有所幫助)。

回答

2

創建一個不可變基類作爲基類的子類。 不可變基地應實現final覆蓋edit()和delete(),它們什麼都不做或拋出一個錯誤。

決賽,讓所有不變的孩子們保證不能夠編輯或刪除此策略的

獎金

  • 容易檢查的對象是不可變的通過測試的instanceof不可改變基地

  • 很容易對矯正它延伸

改變從一成不變的,然後再返回對象
+0

因此,如果我理解正確,層次結構將如下所示:Base-> Immutable_Base-> Immutable_Children和Base-> Mutable_Children?到那時,我會更好地讓Mutable_Base類放置在Base和Mutable_Children類之間? – 2012-01-12 05:52:26

+1

恕我直言Mutable_Base是不必要的,因爲Mutable是基本情況。然而這取決於你和你的美感。有些人強烈喜歡他們的班級樹木中的對稱性。 – 2012-01-12 06:03:13

0

我喜歡Java的這種方法。拋出一個異常。創建一個UnsupportedOperationException,對於那些不應該使用特定方法的實現,請拋出一個讓用戶知道他們不能在此實現中使用此功能。

+0

我仍然必須重寫'edit()'和'delete()'方法來拋出異常,但是?而且我必須在每一個不可改變的課程中這樣做,這個課程看起來並不很乾。雖然拋出一個異常似乎比用我必須說的空方法重寫更有用。 – 2012-01-12 05:50:51

+1

您將不得不重寫該方法,但我不確定單行異常拋出是否真的違反了任何DRY原則。如果你只是想減少重寫次數,你可以簡單地創建一個抽象類來引發適當的異常,而你的不可變對象只是簡單地擴展它。 – cspray 2012-01-12 05:52:57

0

另一個想法是我想拋出一個可能的解決方案。類可以實現看起來像下面的界面:

Interface Immutable { 
    const immutable = true; 
} 

,然後抽象基類可以寫delete()edit()方法與

if (!$this->immutable) { 
    //do_stuff 
} 

這也很好地類的其他分類延長,像NonDeletable和NonEditable,以允許更細粒度的行爲。

2

實際上,創建具有空方法或拋出錯誤的類是很糟糕的 - 這種方法令人困惑,它們佔用空間並且什麼也不做。

更好的方法是將不可變類作爲基類,並使可變類通過添加修改方法來擴展它。這樣每個班級只有那些真正屬於那裏的方法。

0

這是超短期的解決方法,讓你的方法最終並啓動它:

if(self::class!=static::class) return;#or throw an error 

它不會阻止繼承本身,但方法不會在兒童類工作(有錯誤或不 - 高達您)。

0

從PHP 5.4開始,您可以使用Traits

例如,你可以做一個基類,它僅包含所有子類有方法:

class EntityManager { 
    public function create() {/*...*/} 
    public function retrieve() {/*...*/} 
} 

則你可以定義幾個特質:

trait EditTrait { 
    public function edit() {/*...*/} 
} 

trait DeleteTrait { 
    public function delete() {/*...*/} 
} 

,那麼你會創建一個像這樣的不可變的子類:

class LogManager extends EntityManager { 
    ... 
} 

而且可變子類如th是:

class ContactManager extends EntityManager { 
    use EditTrait; 
    use DeleteTrait; 

    ... 
} 

性狀有超過一些其他的解決方案的一些優點在這裏如:

  • 的代碼沒有重複。
  • 單個基類。
  • 不工作或沒有意義的方法,不會出現在不支持它們的類上(對文檔和apis尤其重要)。