我正在研究SOLID原则,界面隔离原则让我很难在这样的场景中理解。
基本上,我有一组对象......用户......使用界面。
public interface IUserInfo
{
string Name { get; }
string Extension { get; }
}
问题是在某些情况下,继承此接口的类将不使用扩展。所以为了解决这个问题,它只返回一个空字符串。
现在,从技术上讲这很好,因为字符串绑定到UI。所以它只会显示该字段的空字符串。
但是,这违反了接口隔离原则。建议的是拆分这些接口。
但是后来我遇到了我想在集合中使用这个接口的问题,请考虑一下:
public interface IUserExtension : IUserInfo
{
string Extension { get; }
}
public ObservableCollection<IUserInfo> StoredUserInfos { get; set; } = new ObservableCollection<IUserInfo>()
{
new User1(),
new User2(),
};
public class User1 : IUserExtension
{
public string Name { get; } = "Alex";
public string Extension { get; } = "(715) 925";
public override string ToString()
{
return Name;
}
}
public class User2 : IUserInfo
{
public string Name { get; } = "Daniel";
public override string ToString()
{
return Name;
}
}
我无法绑定到此集合的索引并获取Extension,因为它是一个IUserInfo接口。巧合的是,我也无法将其作为IUserExtension的集合,因为User2类并没有实现它。
实现这一目标的唯一方法是根据我的意识使用模式匹配
if (UserIndex != -1)
{
var userInfo = StoredUserInfos[UserIndex];
Extension = userInfo is IUserExtension info ? info.Extension : "No Extensions";
Name = userInfo.Name;
}
但这会增加代码的复杂性,并且可能违反其他规则,因为它正在检查类型。
在这种情况下,最好的解决方案是实现一个实现接口的抽象类,而默认实现是一个空字符串吗?
答案 0 :(得分:0)
这是一个困难的问题,但是我要伸出手来试图回答。
IUserInfo接口中的包含扩展是否违反了ISP?我想是的,不是。
假设您想在IUserInfo界面中包含MiddleName属性。中间名是不是每个人都有的,但您可能不想将其添加到单独的界面。与Name属性一起,它们是一个有凝聚力的单元,即它们属于一起。
在这种情况下,您可能希望返回一个空字符串(如上所示)或类似的字符串。 (对于具有行为的更复杂的对象,Null Object模式是一个更好的解决方案。)
因此,如果我们回到上面的问题,您是否将Extension视为属于某个接口的东西?可能不是。再次,让我们设想将EmailAddress添加到IUserInfo接口。与Extension一起,他们建立了一个有凝聚力的单位,并在概念上代表联系方式。如果你要将它们提取到一个单独的界面中,你仍然会有一些没有扩展名的用户,在这种情况下你想要返回一个空字符串(或类似的)。
因此,在回答您的问题时,如果您不太可能使用任何其他属性扩展接口,我认为您可以在IUserInfo接口中保留Extension。否则,创建一个表示联系人详细信息概念的界面,但如果用户没有扩展名,则仍返回空字符串。