具有可选特性的框架接口的接口隔离原则
Interface segregation principle for a framework interface with optional features
我正在设计一个身份验证框架。我需要框架的用户来实现数据访问逻辑,因为这不是框架的主要目的,我想允许多种数据访问方法(SQL、NoSQL、缓存等)我不' 在我的框架内实现它。我的框架通过一个名为 IUserStore 的接口使用此逻辑,但问题是,我的接口中有某些方法仅在某些功能处于活动状态时使用,否则不使用。例如,仅当启用双因素身份验证时,框架才会尝试通过 GetTwoFactorInfo 方法访问双因素信息。
我的问题是关于接口隔离原则。是否可以保留界面原样并在文档中解释用户需要实现 GetTwoFactorInfo 只有当用户想要使用双因素身份验证并抛出 NotImplementedException否则呢?或者我应该为每个可选功能分离接口并在文档中解释用户应该实现并向服务提供商注册此接口以便能够使用该功能?第二种方法的一个问题是,当向构造函数注入实现这些接口的服务时,我需要检查这些功能是否处于活动状态,否则我会收到错误消息,因为服务未注册并且我正在尝试从服务提供商访问这些服务。这导致我的框架更加复杂 类.
处理这个问题的最佳方法是什么?
您建议的两种方法都存在实际问题,但让客户抛出 NotImplementedException
的计划要糟糕得多。
让我们来看看它们:
选项 1
leave the interface as it is and explain in the documentation that user needs to implement GetTwoFactorInfo only if user wants to use two factor authentication and throw NotImplementedException otherwise
好吧,这可能适用于您今天遇到的问题,但软件设计是关于您明天将遇到的问题。如果您在框架的未来版本中添加对不同身份验证方法的支持,会发生什么情况?如果您遵循此模式,那么您将向 IUserStore
添加新方法...但这会破坏现有客户,因为他们不会实现它们!
在某些语言中,您可以通过为抛出异常的新方法提供默认实现来解决这个特定问题,但这首先违背了定义接口的大部分目的——类型系统不再告诉客户他必须实施什么。
此外,此模式仅适用于 pre-existing 接口。如果您添加一个新的身份验证方法,要求客户端实现一个 new 接口,那么您将重新考虑类似第二个选项的东西,然后如果版本控制策略。恶心
选项 2
separate interface for each optional feature and explain in the documentation user should implement and register this interface to service provider to be able to use that feature
这要好得多,但也不是很好,因为它引入了您框架的客户端必须遵循的隐藏规则。了解这些规则的所有方法都令人沮丧——阅读文档、排除错误等。
虽然这是许多依赖注入系统中的常见问题,而且很多人似乎并不介意,但是随着隐藏规则的交互系统的积累,事情变得非常复杂。
选项 3
我不知道你现在如何启用这个 2-factor 功能,但我建议你让你的客户通过调用一个将隐含依赖项作为参数的方法来启用此功能,比如
void enable2FactorAuth(I2FactorInfoStore store)
然后所有的潜规则都消失了。您的系统确保您无法启用该功能,除非您已经实现了所需的接口。简单。
如果您认为如果不进行编程,您将失去配置产品的能力,那么我想提醒您,您没有具有该功能。如您所说,客户必须编写代码才能使用 2 因素身份验证。他们必须实施商店。要求他们调用一个方法来启用它只会改进这段代码,因为现在很明显为什么他们必须在第一名.
我正在设计一个身份验证框架。我需要框架的用户来实现数据访问逻辑,因为这不是框架的主要目的,我想允许多种数据访问方法(SQL、NoSQL、缓存等)我不' 在我的框架内实现它。我的框架通过一个名为 IUserStore 的接口使用此逻辑,但问题是,我的接口中有某些方法仅在某些功能处于活动状态时使用,否则不使用。例如,仅当启用双因素身份验证时,框架才会尝试通过 GetTwoFactorInfo 方法访问双因素信息。
我的问题是关于接口隔离原则。是否可以保留界面原样并在文档中解释用户需要实现 GetTwoFactorInfo 只有当用户想要使用双因素身份验证并抛出 NotImplementedException否则呢?或者我应该为每个可选功能分离接口并在文档中解释用户应该实现并向服务提供商注册此接口以便能够使用该功能?第二种方法的一个问题是,当向构造函数注入实现这些接口的服务时,我需要检查这些功能是否处于活动状态,否则我会收到错误消息,因为服务未注册并且我正在尝试从服务提供商访问这些服务。这导致我的框架更加复杂 类.
处理这个问题的最佳方法是什么?
您建议的两种方法都存在实际问题,但让客户抛出 NotImplementedException
的计划要糟糕得多。
让我们来看看它们:
选项 1
leave the interface as it is and explain in the documentation that user needs to implement GetTwoFactorInfo only if user wants to use two factor authentication and throw NotImplementedException otherwise
好吧,这可能适用于您今天遇到的问题,但软件设计是关于您明天将遇到的问题。如果您在框架的未来版本中添加对不同身份验证方法的支持,会发生什么情况?如果您遵循此模式,那么您将向 IUserStore
添加新方法...但这会破坏现有客户,因为他们不会实现它们!
在某些语言中,您可以通过为抛出异常的新方法提供默认实现来解决这个特定问题,但这首先违背了定义接口的大部分目的——类型系统不再告诉客户他必须实施什么。
此外,此模式仅适用于 pre-existing 接口。如果您添加一个新的身份验证方法,要求客户端实现一个 new 接口,那么您将重新考虑类似第二个选项的东西,然后如果版本控制策略。恶心
选项 2
separate interface for each optional feature and explain in the documentation user should implement and register this interface to service provider to be able to use that feature
这要好得多,但也不是很好,因为它引入了您框架的客户端必须遵循的隐藏规则。了解这些规则的所有方法都令人沮丧——阅读文档、排除错误等。
虽然这是许多依赖注入系统中的常见问题,而且很多人似乎并不介意,但是随着隐藏规则的交互系统的积累,事情变得非常复杂。
选项 3
我不知道你现在如何启用这个 2-factor 功能,但我建议你让你的客户通过调用一个将隐含依赖项作为参数的方法来启用此功能,比如
void enable2FactorAuth(I2FactorInfoStore store)
然后所有的潜规则都消失了。您的系统确保您无法启用该功能,除非您已经实现了所需的接口。简单。
如果您认为如果不进行编程,您将失去配置产品的能力,那么我想提醒您,您没有具有该功能。如您所说,客户必须编写代码才能使用 2 因素身份验证。他们必须实施商店。要求他们调用一个方法来启用它只会改进这段代码,因为现在很明显为什么他们必须在第一名.