我正在创建一些课程,并且我需要征求您的意见。让我们想象一下这种情况:
我们有抽象类A
:
abstract class A {
public int Id {get; set;}
}
我们有三个类实现它B
,C
和D
:
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
,C
和D
实现他们所需要的。问题是当我使用IWithCategories
时,我还需要来自A
的属性。
对此有什么好处?
我的想法是:
我从名为A
的{{1}}中提取界面。 IA
当然会实施A
。
接口IA { int Id {get;组;} }
抽象类A:IA { public int Id {get;组;} }
IA
和IWithComments
将展开IWithCategories
:
interface IWithCategories:IA { 列表类别{get;组;} }
interface IWithComments:IA { 列表评论{get;组;} }
然后IA
,B
和C
可以实现它们:
B类:A,IWithCategories,IWithComments { 公共列表评论{get;组;} 公共列表类别{get;组;} }
C类:A,IWithCategories { 公共列表类别{get;组;} }
D班:A,{ 公共列表评论{get;组;} }
我知道此时类D
,B
和C
不需要扩展抽象类D
, BUT 一些将在所有类中共享的实现,如equals,string和一些受保护的方法。
这种方法可以接受吗?
编辑:
我正在使用Xamarin编写iOS应用程序,我开始只使用类A
,A
,B
和C
。有一点我遇到了一种情况,我正在创建一个ViewController,它应该用于所有具有D
字段的类,这就是我想出提取接口的想法。但是,我还需要调用一个Web服务,我需要在Comments
上声明Id
,现在我正在考虑如何处理这个问题。希望它有所帮助。
答案 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
如何实现IWithCategories
,IWithComments
和Id
属性的继承者无法在接口定义的合同中定义。
但是,您可以设想沿着这些方向实施,
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 : IA
和IWithComments : IA
你要雇用single responsibility principle。另请注意,命名可以反映更多.NET约定ICategorizable
和ICommentable
。这些不是有效的词,而是表达了这个想法。
还要记住,接口应该提供一些功能。有了setter,就会像Jodreli写的那样打开你的API。
关于第3点:
在这一点上真的很难建议,因为你的例子真的很抽象和含糊。最终的实施可能因B,C和D类的原因而有所不同。
这里的一个提示是你应该promote the composition rather than inheritance并且还要确保B C和D类真的是A概念的好例子。