簡體   English   中英

為什么削弱前提條件不違反Liskov替代原則

[英]Why weakening a precondition does not violate Liskov substitution principle

我正在詳細了解LSP,並且確實了解了為什么加強先決條件違反了該原則(使用http://www.ckode.dk/programming/solid-principles-part-3-liskovs-substitution-principle/#contravariance中的示例):

public class SuperType  
{  
    public virtual string FormatName(string name)  
    {  
        if (string.IsNullOrEmpty(name))  
            throw new ArgumentException("name cannot be null or empty", "name");  
        return name;  
    }  
}  

//VIOLATING ONE
public class LSPIllegalSubType : SuperType  
{  
    public override string FormatName(string name)  
    {  
        if (string.IsNullOrEmpty(name) || name.Length < 4)  
            throw new ArgumentException("name must be at least 4 characters long", "name");  
        return name;  
    }  
}  

在這里,我可以清楚地看到,對基類有效的內容將因其派生而失敗。 換句話說,如果不更改行為,我將無法用其派生類替換基類。

現在,以下方法被認為是合法的,因為它削弱了先決條件:

    public class LSPLegalSubType : SuperType  
{  
    public override string FormatName(string name)  
    {  
        if (name == null)  
            throw new ArgumentNullException("name");  
        return name;  
    }  
}  

引用站點:這是完全合法的,因為超類型的任何有效參數在子類型中也將有效。

好吧,但是無效的參數呢? 如果我有一個用無效參數(例如空名稱)調用SuperType的代碼,它將失敗。 如果將其替換為子類型,則由於條件較弱,相同的調用不會失敗。 因此從這個意義上講,我不能用子類型替換超類型,因為它也會改變行為。 我很困惑。

如果削弱先決條件,則子類型仍然與需要超類型的位置兼容。 它可能不會在基類正常運行的地方拋出異常,但這沒關系,因為拋出更少的異常不會破壞使用代碼。 如果調用代碼是圍繞在某些地方拋出異常的假設構建的,並將其用於應用程序的主控制流,則應該重寫使用方代碼。

另外,我認為您的第二個代碼示例是錯誤的。

如果必須始終強制執行基類的前提條件,那么更好的實現方法是創建一個封裝這些規則的數據類型,並將其作為參數傳遞。 這樣,它就不屬於子類,它是新類的構造函數的一部分。

例如:

public class UserName 
{
    public string Value { get; }

    public UserName(string value)
    {
        if (string.IsNullOrWhitespace(value) || value.Length < 4)
            throw new ArgumentNullException(nameof(value));

        Value = value;
    }
}

public class BaseClass 
{
    public virtual void Foo(UserName username) 
    { 
        //No precondition checks required here 
    }
}

public class DerivedClass : BaseClass
{
    public override void Foo(UserName username) 
    {
        //No precondition checks required here
    }
}

帶有前置條件和后置條件的方法表明,當調用者滿足前置條件時,它將確保退出時滿足后置條件。 然而,合同沒有規定會發生什么,如果該前提條件成立-它仍然允許該方法成功完成。 因此,子類型會削弱先決條件,因為如果調用者無法滿足子類型的先決條件,則它們將無法對方法的行為做出任何假設。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM