对象集合的接口隔离原则

Interface Segregation Principle on a collection of objects

我正在学习 SOLID 原则,接口隔离原则让我在这种情况下很难理解。

基本上,我有一组对象...用户...使用接口。

public interface IUserInfo 
{
    string Name { get; }
    string Extension { get; }
}

问题是在某些情况下,继承此接口的 class 不会使用扩展名。所以为了解决这个问题,它只是 returns 一个空字符串。

现在,从技术上讲这没问题,因为该字符串已绑定到 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;
        }
    }

我无法绑定到此集合的索引并获取扩展,因为它是一个 IUserInfo 接口。巧合的是,我也不能将其作为 IUserExtension 的集合,因为 User2 class 没有实现它。

据我所知,唯一可行的方法是使用模式匹配

        if (UserIndex != -1)
        {
            var userInfo = StoredUserInfos[UserIndex];
            Extension = userInfo is IUserExtension info ? info.Extension : "No Extensions";
            Name = userInfo.Name;
        }

但这会增加代码的复杂性,并且可能会违反其他规则,因为它正在检查类型。

在这种情况下,最好的解决方案是实现一个实现接口的抽象 class 并且默认实现是一个空字符串吗?

这是一个困难的问题,但我会伸出我的脖子并尝试回答。

在IUserInfo 接口中包含Extension 是否违反了ISP?我认为是和否。

假设您想在 IUserInfo 界面中包含一个 MiddleName 属性。中间名不是每个人都有的,但您可能不想将其添加到单独的界面中。与名称 属性 一起,它们是一个有凝聚力的单元,即它们属于一起。

在这种情况下,您可能希望 return 一个空字符串(如上所示)或类似内容。 (对于具有行为的更复杂的对象,Null Object 模式是更好的解决方案。)

因此,如果我们 return 解决您上面的问题,您是否将 Extension 视为属于接口本身的东西?可能不会。同样,让我们​​想象一下将 EmailAddress 添加到 IUserInfo 接口。与 Extension 一起,它们构成了一个有凝聚力的单元,并在概念上表示联系方式。如果你要将它们提取到一个单独的界面中,你仍然会有一些没有扩展名的用户,在这种情况下你会想要 return 一个空字符串(或类似的)。

因此,在回答您的问题时,如果您不太可能使用更多属性扩展接口,我认为您可以将 Extension 保留在 IUserInfo 接口中。否则,创建一个表示联系人详细信息概念的界面,但如果用户没有分机,则仍然 return 是一个空字符串。