并非所有接口成员都将实现

是不是通过说某些类没有实现“某些”接口成员是很常见的,因为在某些情况下它们不适用,所以你在方法体中抛出一个未实现的错误?

例如,假设我创建了一个接口IAPIAuthentication,它将服务器作为类的合同,这些类将执行对第三方API(例如Facebook)的身份validation请求,以及我们稍后将要实现的其他API。

所以我的IAPIAuthentication接口可能具有以下属性:

// The URI that the auth HTTP Request will go to (minus any querystring values, this is just the base) AuthenticationURI (property) // unique ID for your API account with whatever API you are using (Facebook, Picasa, whatever) ClientID (property) // unique secret code also obtained when you sign up for an API account and used in auth calls ClientSecret (property) // a confirmation code sent back from the AuthenticationVerificationCodeID (method) // a boolean property set to true if an AuthenticationVerificationID was received back after an Auth request AuthenticationWasSuccessful (property) // sends the actual HTTP Request to the specified Uri SendRequest() 

好吧,在许多情况下,其他API在其身份validation过程中需要相同的信息(例如PhotoBucket等)

好的,所以我创建了这个接口,当我为这些API创建包装器时将用于各种实现,并且当我开始使用一些包装器创建function时,这一点的全部意义是在结构和重用方面创建一些良好的通用性我将在这里建立这些通用接口。 这些是大多数NVP API的基本构建块,因此无论我正在实现什么API,或者我在这里创建的任何接口中的至少90%的值,我在这些接口中放置的内容通常都会被使用。

所以我将创建一个类,例如实现该接口的FacebookAuth。 所有发现和花花公子。 好的,下次我在一个新项目上工作时我说嘿,我还要实现那个界面,保持团队标准/模式来创建第三方包装项目)我知道我需要让我们说全部那些属性但可能减去一两个,因为该提供者在其身份validation过程中不需要该信息。 让我们说它只是一个它不需要的东西。

所以我的问题是这些:

  1. 当我稍后开始创建所有这些第三方API包装器项目时,我的方法是否对重用和一致性的目标有意义?

  2. 好的,一般来说,如你知道的那样接口,如果有人试图在你的子类中使用该方法,你可以通过至少在.NET中抛出一个未实现的exception来避免实现某种接口方法。 我不确定属性……如果你绝对不得不(罕见的一次性),你怎么忽略它们中的任何一个。 因此,期望您的界面永远不会“完美”,所有成员将始终全面使用100%,这是“正常”吗? 我的意思是可以说只放入将100%使用的元素。 好吧,但这取决于……因为有些API在大多数情况下会在这种情况下全部使用..只有一些一次性不会……所以对我来说,包含一些可能不会被使用的东西仍然是有意义的在其他人。

我只想根据经验得到一些输入……对于Interfaces比我更熟悉的开发人员。 我没有多少使用接口..我得到它们是什么(合同,yada yada),但我正在试图找出它们的最佳用途,我真的认为这是一个很好用的。 我也会有抽象类……只有少数所以我知道两者之间的区别。 我只是想知道是否可以接受非完美的接口。 我猜这就是为什么他们的API版本正确? 但是即使在现有版本中,您也会有一些类没有完全实现接口的所有成员,但实现了该接口的一致性和重用,无论您的应用程序或包装器如何整体…

我希望我没有太多絮絮叨叨。 如果我不清楚,请告诉我。 并保持在我的ind我的上面的例子并不是真的完整,但得到了重点。

通常不希望具有部分实现的接口。

我的建议是分离您的顾虑,即将您的界面分成几个接口,以便实现完整和自主。

但是,有些情况下,统一界面的好处超过了关注点的分离,恕我直言,其中很少有这些,但它们肯定存在。 一个例子是.NET BCL,其中一些ICollection类是只读的,因此不支持AddRemoveClear 。 为避免使用控制流的exception, ICollection提供了一个IsReadOnly属性来指示不支持这些方法。

如果您仍然决定为所有代码保留单个接口,则抛出NotSupportedException而不是NotImplementedException ,从而选择不显式实现该操作。

根据您的描述,您将创建一个将由多个类似服务实现的界面。 由于我不知道您的接口作者/实现之间的要求,约束或责任分工 ,因此我要考虑一些可用的选项。 这绝不是一份详尽的清单 – 只是那些常见的清单:

  1. 创建一个“超集”公共接口,对于某些实现,可能无法完全实现。 例外报告不支持哪些function。
  2. 创建一个“最低公分母”界面,该界面只包含所有实现都可以支持的成员。 没有不受支持的exception抛出,因为每个人都需要支持所有function。
  3. 为每个实现服务创建完全独立的接口(这有效地破坏了通用的统一接口的价值)。
  4. 作为#1的变体,添加可以报告支持哪些function的属性/方法(因此您不会使用exception作为检查支持的function的方法)。
  5. 作为#2的变体,创建inheritance的接口,逐步添加其他function。

选项#1可能使编写可靠代码变得困难。 你总是发现自己在try / catch块中包装每个方法调用 – 这可能变得不可读。 更糟糕的是,如果您忘记在某处执行此操作,则可以通过调用堆栈传播未处理的exception,这可能本身就是破坏性的。 但是,对于那些实现接口来处理的人来说,这种方法最简单 – 如果不支持某个function,只需抛出一个NotSupportedException就行了。

选项#2需要进行重要分析才能正确识别支持function的真正常见子集。 如果您错误地猜测所有实现程序支持某个function的能力,这种方法会变得更加复杂,您可能会发现自己在情境#1中默认情况下 – 要求您添加所有必要的逻辑来处理潜在的exception。

选项#3基本上是:“我放弃。这里没有通用接口”。 有时这是一个可接受的答案 。 试图楔入一个自然不会出现的接口可能比简单地编写单独的(不相关的)接口或实现类更糟糕。 在这种情况下,您通常会将每个已知实现和组function的“策略”实现为更粗粒度的方法,这些方法可以在所有情况下可靠地实现。

选项#4很有用,它允许您在调用之前首先检查function是否受支持。 如果调用,实现者仍然可能抛出NotSupportedException,不同之处在于您不会调用开头不支持的实现。 这里的问题是您需要设计一种机制,允许消费者测试支持哪些function。 这种方法不是面向对象或特别可扩展(如果你的界面发展),但它很简单。

选项#5尝试通过分区function改进#2 – 可能没有有意义的“最低公分母”接口 – 相反,可能有一系列相关接口可以一起使用。 此选项还可能导致零碎接口的扩散,这可能成为维护挑战。 从好的方面来说,这种方法允许您通过尝试转换为特定接口来轻松测试实现支持哪些function。 它比某种SupportedCapabilities枚举更具可扩展性。 在这种方法中,每个实现都应该支持所有接口或支持任何接口。 这并不总是可以实现,并且与选项#2中描述的挑战相冲突。

正如谚语所说:“ 任何编程问题都可以通过添加另一层抽象来解决 ”。 但是,您需要确定哪些抽象级别对于您要解决的问题是必要的或适当的。

除了这里的其他答案之外,如果你真的必须提供一个不完整的接口实现,那么当访问不支持的成员时你应该抛出NotSupportedException 。 您还可以通过使用显式接口实现来降低这些成员的可见性。

 public interface IExample { void Add(int id); void Remove(int id); bool Contains(int id); } public class ReadOnlyExample : IExample { private readonly HashSet _ids; public ReadOnlyExample(IEnumerable ids) { _ids = new HashSet(ids); } public bool Contains(int id) { return _ids.Contains(id); } void IExample.Add(int id) // explicit interface implementation { throw new NotSupportedException("This example is read-only!"); } void IExample.Remove(int id) // explicit interface implementation { throw new NotSupportedException("This example is read-only!"); } } 

我同意哈佛的回答。 此外,关于如何处理属性,您可以让不受支持的属性getter / setter像方法一样抛出exception。 例如:

 public string ClientID { get { throw new NotSupportedException(); } }