在抽象类和接口中使用相同的字段名称是否可以?

时间:2014-07-22 08:01:05

标签: c# oop inheritance interface

我正在创建一些课程,并且我需要征求您的意见。让我们想象一下这种情况:

我们有抽象类A

abstract class A {
  public int Id {get; set;}
}

我们有三个类实现它BCD

class B : A {
  public List<string> Comments {get; set;}
  public List<string> Categories {get; set;}
}

class C : A {
  public List<string> Categories {get; set;}
}

class D : A {
  public List<string> Comments {get; set;}
}

正如您所看到的,一些属性很常见,我想将它们提取到另一个类/接口。所以理论上我可以创建以下接口:

interface IWithCategories {
  List<string> Categories {get; set;}
}

interface IWithComments {
  List<string> Comments {get; set;}
}

BCD实现他们所需要的。问题是当我使用IWithCategories时,我还需要来自A的属性。

对此有什么好处?

我的想法是:

  1. 我从名为A的{​​{1}}中提取界面。 IA当然会实施A

    接口IA {   int Id {get;组;} }

    抽象类A:IA {   public int Id {get;组;} }

  2. IAIWithComments将展开IWithCategories

    interface IWithCategories:IA {   列表类别{get;组;} }

    interface IWithComments:IA {   列表评论{get;组;} }

  3. 然后IABC可以实现它们:

    B类:A,IWithCategories,IWithComments {   公共列表评论{get;组;}   公共列表类别{get;组;} }

    C类:A,IWithCategories {   公共列表类别{get;组;} }

    D班:A,{   公共列表评论{get;组;} }

  4. 我知道此时类DBC不需要扩展抽象类D BUT 一些将在所有类中共享的实现,如equals,string和一些受保护的方法。

    这种方法可以接受吗?

    编辑:

    我正在使用Xamarin编写iOS应用程序,我开始只使用类AABC。有一点我遇到了一种情况,我正在创建一个ViewController,它应该用于所有具有D字段的类,这就是我想出提取接口的想法。但是,我还需要调用一个Web服务,我需要在Comments上声明Id,现在我正在考虑如何处理这个问题。希望它有所帮助。

2 个答案:

答案 0 :(得分:1)

好的,为什么接口需要setter,我会假设他们没有。接口是否需要公开List<string>而不是IList<string>,我假设没有。然后你有这些接口定义。

public interface IWithCategories {
  IList<string> Categories { get; }
}

public interface IWithComments {
  IList<string> Comments { get; }
}

现在,如果这些接口是public,那么无论谁选择这样做,都无法阻止它们被实现。如果你保留它们internal,只有你的装配才能使用它们。

如果您希望abstract class A实现这些接口,您可以将其定义为

public abstract class A : IWithCategories, IWithComments
{
    abstract public int Id { get; }

    abstract public IList<string> Categories { get; }

    abstract public IList<string> Comments { get; }
}

A如何实现IWithCategoriesIWithCommentsId属性的继承者无法在接口定义的合同中定义。

但是,您可以设想沿着这些方向实施,

public class B : A
{
    private readonly int id;
    private readonly List<string> categories;
    private readonly List<string> comments;

    public B(
            int id,
            IEnumerable<string> categories
            IEnumerable<string> comments)
    {
        this.id = id;
        this.categories = (categories ?? Enumerable.Empty<string>()).ToList();
        this.comments = (comments ?? Enumerable.Empty<string>()).ToList();
    }

    public override int Id
    {
        get { return this.id; }
    }

    public override IList<string> Categories
    {
        get { return this.categories; }
    }

    public override IList<string> Comments
    {
        get { return this.comments; }
    }
}

答案 1 :(得分:1)

关于品脱1:

如果抽象类是唯一的,则IA接口有多个实现,这很好。然后没有理由创建额外的抽象层。特别是当抽象类的实现部分基于该方法时。

关于第2点:

IWithCategories : IAIWithComments : IA

你要雇用single responsibility principle。另请注意,命名可以反映更多.NET约定ICategorizableICommentable。这些不是有效的词,而是表达了这个想法。

还要记住,接口应该提供一些功能。有了setter,就会像Jodreli写的那样打开你的API。

关于第3点:

在这一点上真的很难建议,因为你的例子真的很抽象和含糊。最终的实施可能因B,C和D类的原因而有所不同。

这里的一个提示是你应该promote the composition rather than inheritance并且还要确保B C和D类真的是A概念的好例子。