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

本文关键字:字段 抽象类 接口 是否 | 更新日期: 2023-09-27 18:14:09

我正在创建一些类,我需要征求您的意见。让我们想象一下这样的情况:

我们有一个抽象类A:

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

我们有三个类实现它B, CD:

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;}
}

B, CD实现他们需要的。问题是,当我使用IWithCategories时,我还需要A的属性。

这个问题有什么好的解决方案?

我的想法如下:

  1. 我从A中提取接口,称为IAA当然会实现IA

    interface IA {int Id{获取;设置;}}

    抽象类A: IA {公共int Id{获取;设置;}}

  2. IWithCommentsIWithCategories将扩展IA:

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

    interface IWithComments: IA {列表注释{get;设置;}}

  3. 然后B, CD可以实现它们:

    类B: A, IWithCategories, IWithComments {公共列表评论{get;设置;}公共列表类别{获取;设置;}}

    类C: A, IWithCategories {公共列表类别{获取;设置;}}

    类D: A, {公共列表评论{get;设置;}}

我知道在这一点上,B, CD类不需要扩展抽象类A但是它有一些实现,将在所有类之间共享,如equals, string和一些受保护的方法。

这个方法可以接受吗?

编辑:

我正在使用Xamarin编写一个iOS应用程序,我开始只有类A, B, CD。在某种程度上,我遇到了一种情况,我正在创建一个ViewController,应该用于所有具有Comments字段的类,这是当我提出提取接口的想法。但是,我还需要调用一个web服务,我需要在A上声明Id,现在我正在考虑如何处理这个问题。

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

好吧,为什么接口需要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:

如果您有多个IA接口的实现,并且抽象类是唯一的,那么这是很好的。那么就没有理由创建额外的抽象层了。特别是当实现抽象类基部分依赖于该方法时。

关于第2点:

IWithCategories : IAIWithComments : IA

你应该采用单一责任原则。还要注意,命名可以反映更多的。net约定ICategorizableICommentable。那些话不正确,但表达了意思。

还要记住接口应该提供一些功能。如Jodreli所写的那样,在里面设置setter将打开你的API。

关于第3点:

在这一点上真的很难建议,因为你的例子真的很抽象和模糊。最终的实现可能因B、C和D类的原因而异。

这里的提示是,您应该促进组合而不是继承,并确保类B、C和D确实是A概念的好例子。