对象集合

时间:2017-11-29 01:20:35

标签: c# interface solid-principles

我正在研究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;
        }

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

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

1 个答案:

答案 0 :(得分:0)

这是一个困难的问题,但是我要伸出手来试图回答。

IUserInfo接口中的包含扩展是否违反了ISP?我想是的,不是。

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

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

因此,如果我们回到上面的问题,您是否将Extension视为属于某个接口的东西?可能不是。再次,让我们设想将EmailAddress添加到IUserInfo接口。与Extension一起,他们建立了一个有凝聚力的单位,并在概念上代表联系方式。如果你要将它们提取到一个单独的界面中,你仍然会有一些没有扩展名的用户,在这种情况下你想要返回一个空字符串(或类似的)。

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