public abstract class Entity
{
public abstract IList<string> Values { get; set; }
}
public class GenericEntity : Entity
{
private IList<string> _Values;
public override IList<string> Values
{
get { return _Values; }
set
{
ValidateValues(value);
_Values = value;
}
}
protected virtual void ValidateValues(IList<string> values)
{
// many validation conditions here, if values validation fails, throws...
}
}
public class AEntity : GenericEntity
{
protected override void ValidateValues(IList<string> values)
{
base.ValidateValues(values);
// there is an extra validation condition
if(values.Count < 1) throw InvalidOperationException("values count!");
}
}
public class BEntity : GenericEntity
{
protected override void ValidateValues(IList<string> values)
{
base.ValidateValues(values);
if(values.Count < 2) throw InvalidOperationException("values count!");
}
}
当GenericEntity
用户的继承者有额外的验证条件(检查Values
项的数量)时,这是否违反了LSP?我认为是因为先决条件已经得到加强。
这是否意味着我应该删除GenericEntity
类并让AEntity
和BEntity
成为Entity
的直接继承者?但它会导致两个类中重复的代码。
另外我考虑另一种选择:当Entity
获得对某个抽象类Validation
实例的引用时。这是问题最优雅的解决方案吗?
答案 0 :(得分:1)
目前完全没有“违反LSP”,因为您没有更改类别基础验证。
不幸的是,其他开发人员可以覆盖ValidateValues
而无需调用基本方法......
避免这种情况的解决方案是创建两种方法:
public void ValidateValues(IList<string> values) {
// many validation conditions here, if values validation fails, throws...
ValidateValuesEx();
}
protected virtual void ValidateValuesEx() {
// for extension
}
答案 1 :(得分:0)
通过代码设计,子类可以通过不调用base.ValidateValues
完全绕过验证。我不知道这是否违反了LSP,但你应该考虑这个问题。如果您做了一些小改动,您可以确保每次调用GenericEntity.ValidateValues
中发生的验证。
public class GenericEntity : Entity
{
private IList<string> _Values;
public override IList<string> Values
{
get { return _Values; }
set
{
ValidateValues(value);
_Values = value;
}
}
private void ValidateValues(IList<string> values)
{
// many validation conditions here, if values validation fails, throws...
this.OnValidateValues(values);
}
protected virtual void OnValidateValues(IList<string> values)
{
//do nothing. Let sub-classes override.
}
}
}
public class AEntity : GenericEntity
{
protected override void OnValidateValues(IList<string> values)
{
if(values.Count < 1) throw InvalidOperationException("values count!");
}
}
在此代码中,GenericEntity控制对子类的调用&#39;验证码。不是相反。父类验证保证始终运行,并且它总是在任何子类验证之前发生。
请注意,无论子类是否调用base.OnValidateValues
。