我有一个项目,其中将抽象地定义相当多的函数和变量getter。我的问题是我应该使用一个抽象类(每个函数抛出NotImplementedException),还是应该只使用一个接口?或者我应该同时使用两者,既可以创建接口,又可以实现接口的抽象类?
注意,即使可以定义所有这些功能等,但这并不意味着它们将全部用于所有用例。例如,身份验证类中的AddUser可以在界面中定义,但由于封闭式用户注册而不会在网站中使用。
答案 0 :(得分:2)
一般来说,通过这种方式思考,可以回答是否使用继承或接口的问题:
在考虑假设时 实现类,是一个案例 这些类型是我在哪里 描述,或者是一个案例 这些类型可以或可以我所做的 描述
例如,考虑IEnumerable<T>
接口。实现IEnumerable<T>
的类都是不同的类。他们可以是一个可枚举的结构,但它们基本上是别的东西(List<T>
或Dictionary<TKey, TValue>
或查询等。)
另一方面,请查看System.IO.Stream
课程。虽然从该抽象类继承的类是不同的(例如FileStream
与NetworkStream
),但它们都是基本流 - 只是不同的类。流功能是定义这些类型的核心,而不仅仅是描述它们提供的一部分类型或一组行为。
通常你会觉得两者兼顾是有益的;定义一个定义行为的接口,然后定义一个实现它并提供核心功能的抽象类。如果合适的话,这将允许您充分利用这两个领域:从功能是核心时继承的抽象类,以及在不是核心时继承的接口。
另外,请记住,通过使用扩展方法,仍然可以在接口上提供一些核心功能。虽然严格来说,这并没有在界面上放置任何实际的实例代码(因为这是不可能的),你可以模仿它。这是LINQ-to-Objects查询函数在IEnumerable<T>
上的工作方式,通过定义用于查询泛型Enumerable
实例的扩展方法的静态IEnumerable<T>
类。
作为旁注,您不需要抛出任何NotImplementedException
个。如果将函数或属性定义为abstract
,那么您不需要(事实上,不能)在抽象类中为它提供函数体;继承类将被强制提供方法体。 他们可能会抛出这样的异常,但这不是你需要担心的事情(并且接口也是如此)。
答案 1 :(得分:1)
如果您未提供任何实现,则使用接口,否则使用抽象类。如果某些方法可能无法在子类中实现,那么创建一个中间抽象类来执行抛出NotSupportedException或类似方法的工作可能是有意义的。
答案 2 :(得分:1)
就个人而言,我认为这取决于“类型”的定义。
如果您要定义一组行为,我会推荐一个界面。
另一方面,如果类型确实定义了“类型”,那么我更喜欢抽象类。我建议保留抽象方法而不是提供空行为。
注意,即使可以定义所有这些功能等,但这并不意味着它们将全部用于所有用例。
如果这是真的,您应该考虑将其分解为多个抽象类或接口。在基类/接口中使用“不合适”的方法确实违反了Liskov Substitution Principle,并且是设计缺陷的标志。
答案 3 :(得分:1)
抽象类的一个优点是可以向抽象类添加新的类成员,其默认实现可以用现有的类成员表示,而不会破坏该类的现有继承者。相反,如果将任何新成员添加到接口,则必须修改该接口的每个实现以添加必要的功能。
如果.net允许接口包含未使用对象字段的属性,方法和事件的默认实现,那将是非常好的。从技术角度来看,我认为通过为每个接口提供一个默认vtable条目列表可以毫不费力地完成这样的事情,这些条目可以用于没有定义所有vtable槽的实现。不幸的是,.net中没有类似的能力。
答案 4 :(得分:0)
当您可以提供部分实现时,应该使用抽象类。如果您不想提供任何实现,请使用接口 - 只需定义。
在你的问题中,听起来似乎没有实现,所以请使用界面。
此外,您应该使用NotImplementedException
关键字声明您的方法/属性,而不是抛出abstract
,以便所有继承者都必须提供实现。
答案 5 :(得分:0)
在某些情况下有效的另一种模式是创建一个非抽象的基类。它有一组定义API的公共方法。这些中的每一个都调用一个Overctedable的Protected方法。 这允许派生类选择它需要实现的方法。 所以例如
public void AddUser(object user)
{
AddUserCore(user);
}
protected virtual void AddUserCore(object user)
{
//no implementation in base
}
答案 6 :(得分:0)
@Earlz我想参考这个:Note, even though all of these functions and such may be defined, it does not mean they will all be used in all use cases.
与“攻击”这个问题的最佳方式直接相关。
你应该瞄准的是最小化这些功能的数量,使它变得无关紧要(或者至少不那么重要)如果你使用或者。所以尽可能地改进设计,你会发现你走哪条路并不重要。
更好的是发布你正在尝试做的高水平,让我们看看我们是否可以提出一些不错的东西。努力实现共同目标的更多大脑将获得更好的答案/设计。