代码之家  ›  专栏  ›  技术社区  ›  Scott Whitlock

这是否违反了Liskov替代原则,如果是,我该怎么办?

  •  4
  • Scott Whitlock  · 技术社区  · 14 年前

    用例:我使用数据模板将视图与视图模型匹配。数据模板通过检查所提供的具体类型的最派生类型来工作,并且它们不查看它提供的接口,因此我必须在没有接口的情况下执行此操作。

    class ReadOnlyText
    {
        private string text = string.Empty;
    
        public string Text
        {
            get { return text; }
            set
            {
                OnTextSet(value);
            }
        }
    
        protected virtual void OnTextSet(string value)
        {
            throw new InvalidOperationException("Text is readonly.");
        }
    
        protected void SetText(string value)
        {
            text = value;
            // in reality we'd NotifyPropertyChanged in here
        }
    }
    
    class WritableText : ReadOnlyText
    {
        protected override void OnTextSet(string value)
        {
            // call out to business logic here, validation, etc.
            SetText(value);
        }
    }
    

    通过重写OnTextSet并更改其行为,我是否违反了 LSP ? 如果是的话,还有什么更好的方法呢?

    4 回复  |  直到 14 年前
        1
  •  9
  •   Community CDub    7 年前

    LSP声明一个子类应该是其超类的substiubable(参见stackoverflow问题 here ). 要问自己的问题是,“可写文本是 只读 可读的

    class ReadableText
    {
        private string text = string.Empty;
        public ReadableText(string value)
        {
            text = value;
        }
    
        public string Text
        {
            get { return text; }
        }
    }          
    
    class WriteableText : ReadableText
    {
        public WriteableText(string value):base(value)
        {
    
        }
    
        public new string Text
        {
            set
            {
                OnTextSet(value);
            }
            get
            {
                return base.Text;
            }
        }
        public void SetText(string value)
        {
            Text = value;
            // in reality we'd NotifyPropertyChanged in here       
        }
        public void OnTextSet(string value)
        {
            // call out to business logic here, validation, etc.       
            SetText(value);
        }
    }     
    

    为了清楚起见,我们在可写类的文本属性上使用新的关键字来隐藏可读类的文本属性。
    http://msdn.microsoft.com/en-us/library/ms173152(VS.80).aspx 使用new关键字时,将调用新的类成员,而不是已替换的基类成员。这些基类成员称为隐藏成员。如果派生类的实例被强制转换为基类的实例,则仍然可以调用隐藏类成员。

        2
  •  8
  •   TheCloudlessSky    13 年前

    只有当 ReadOnlyText.OnTextSet() 承诺要扔。

    public void F(ReadOnlyText t, string value)
    {
        t.OnTextSet(value);
    }
    

    如果这个不扔,你觉得有意义吗?如果不是,那么writeabletext是不可替换的。

    在我看来 WritableText 应该继承自文本。如果 ReadOnlyText ,将其放入文本或它们都继承自的另一个类(继承自 Text )

        3
  •  2
  •   peterchen    14 年前

    如果ReadOnlyText的约定中说“任何设置文本的尝试都会引发异常”,那么您肯定违反了LSP。

    如果没有,代码中仍然有一个尴尬的地方:只读文本的setter。

    IThingieReader
    {
        string Text { get; }
        string Subtext { get; }
        // ...
    }
    
    IThingieWriter
    {
        string Text { get; set; }
        string Subtext { get; set; }
        // ...
    }
    

    …并仅在适当时实现接口。但是,如果必须处理以下情况,则会出现故障:。 Text 是可写的 Subtext 对于许多对象/属性来说,不是,而且是一件很麻烦的事情。

        4
  •  0
  •   Thanos Papathanasiou    14 年前

    是的,如果受保护的重写void OnTextSet(字符串值)也抛出了“invalidooperationexception”类型或从中继承的异常,则不会。