2015-04-01 14 views
1

有一個IUser類。它有一個功能,需要訪問者並允許更改公共屬性。現在修改父級行爲的訪問者層次結構。 Liskov可以嗎?

public IUser 
{ 
    public PermissionMatrix Permissions { get; set; }  

    public void Authorizations(IAuthManager manager) 
    { 
     manager.SetRoles(this); 
    } 
} 

,它可以通過IAuthManager

public IAuthManager 
{ 
    public void SetRoles(IUser user); 
} 

public InternalAuthManager : IAuthManager 
{ 
    public virtual void SetRoles(IUser user) 
    { 
    // sets permissions in user for internal security 
    // according to a complex logic 
    } 
} 

public RestrictInternalAuthManager : InternalAuthManager 
{ 
    public override void SetRoles(IUser user) 
    { 
    base.SetRoles(user); // need to use complex logic of parent 
    // then reverts few permissions based on conditions 
    } 
} 

的類層次我想如果類RestrictInternalAuthManager違反了里氏替換原則來評估訪問。 我一直在爭論是和否,

否:沒有檢查IAuthManager的類型。

是:RestrictInternalAuthManager正在更改InternalAuthManager的後置條件。

這可以保持原樣,還是類需要重構?任何幫助表示讚賞。

回答

2

令Φ(x)爲可證明的關於對象的屬性類型T.然後Φ(Y)的X應爲S型的對象ý真其中S是T.

的子類型現在的問題是,你還沒有真正指定方法的行爲;如果有人會推斷「它設置了權限」,那麼你並沒有真正改變行爲。如果你會說,「這種方法以這種方式進行」,在子類中你會改變它,那麼是的,你會違反LSP。即如果你說「get()檢索一個項目」的隊列和堆棧,但它會是好的,但如果你說「Queue.get()檢索最舊的項目」和「Stack.get()檢索最新的項目」比他們是不同的。

LSP背後的想法是,預期的行爲不會改變,例如,如果您要爲基類編寫測試,那麼如果您提供子類,則所有測試都必須通過。

另一個重要的問題是:我是分類還是繼承?如果我改變超類的行爲,是否需要在子類中進行更改?我只是爲了方便而重用超類的實現嗎?如果是這樣,那就是違規。

也想想如果你需要另一個經理增加一件事情會發生什麼;這可能會很快失控。如果您不確定是否繼承,則最好使用分解代替。

+0

明白了,需要重構我猜。感謝您的努力。 – wonderbell 2015-04-02 20:19:39

1

Liskov替代原則適用於單元測試和tdd。傳遞給基類的測試也應該傳遞任何派生類。如果您正在使用tdd或以其他方式進行具有高代碼覆蓋率的單元測試,那麼如果派生類恢復了某些更改,則測試是否進行了預期更改的基類的測試將失敗。

所以,是的,我認爲它違反了LSP。

「遺傳行爲的恢復」對我也有不好的品味。

我會推薦使用一個抽象的基類來完成常見的事情。要創建兩個派生類,它們只是「添加」一些更改,而不是還原一些繼承的。

+0

從單元測試的角度來考慮整體感知的變化。感謝您的高舉。 – wonderbell 2015-04-02 19:57:34