首页 > 解决方案 > 当实现如此不同时,依赖注入场景中使用的接口和类的设计过程

问题描述

以从网页中提取数据的服务为例(例如 Mercury https://mercury.postlight.com/web-parser/或 Diffobt https://www.diffbot.com/products/automatic/#article)我想要询问有关如何为依赖注入 (DI)/控制反转 (IoC) 场景构建接口和类实现的问题。

我正在尝试确定如何最好地创建一个IPageExtractor接口和后续的具体实现MercuryPageExtractor,并在实际实现完全不同的情况下DiffbotPageExtractor实现该接口。IPageExtractor

显然,这是首先实现接口的全部要点,但我有一个心理障碍,我需要帮助克服。

例如,Mercury 使用密钥和秘密进行身份验证,而 Diffbot 仅使用令牌。好吧,也许这并没有太大的不同,但我感到困惑的是我必须在界面中适应它,当然界面是最低公分母。例如,我是否会传入一组身份验证数据并让具体实现对其进行排序?

另一个不同之处是 Mercury 返回关于网页的 3 条数据,而 Diffbot 返回 20 条(这在技术上可能不准确,但可能存在差异的示例就是我所得到的)。我将如何设计接口和具体实现来处理这个问题?

最后一个显着的区别是,在每种情况下,成功和失败的构成非常不同,成功或失败返回的消息类型(格式、结构、内容)也有很大差异。

你能帮忙想想这个问题吗?

我在 C#/.NET 中工作,但以独立于语言的方式考虑这一点。

标签: c#dependency-injectioninterfaceinversion-of-controlconcreteclass

解决方案


让我们看一下接口驱动的抽象工厂的另一个场景

在开始之前,我们需要清楚接口指定了需要做什么,并带有输入和所需输出的微妙指示。也就是说,它并不强制要求输入和输出都需要很好地定义,因为它们本身也可以被视为合同。如果我们不完全清楚输入和输出的结构是什么,我们可以使用标记接口;那些根本没有任何结构的..

假设我们有一个购物车,我们需要提供付款选项。常见的选择是网上银行、信用卡和贝宝。让我们有这个场景的定义

public interface ICustomerAccountInformation {  }

public interface IPaymentClient {  }  // Identifies whom the payment is intended for

public interface ITransactionDetails : IPaymentClient {  }  // Identifies amount, beneficiary details to be reflected in customer account

public interface IPaymentStatus { }

public interface IPaymentProvider  { 
    IPaymentStatus ProcessPayment(ICustomerAccountInformation customerInfo, ITransactionDetails transaction);

}


public class PayPal : IPaymentProvider  {

    public IPaymentStatus ProcessPayment(ICustomerAccountInformation customerInfo, ITransactionDetails transaction)  {
           /* Open paypal's login page, 
             do its own checks and process payment. 
             Once successfull, send back to referrer with the payment status
           */
    }

public class NetbankingProvider : IPaymentProvider  {

    public IPaymentStatus ProcessPayment(ICustomerAccountInformation customerInfo, ITransactionDetails transaction)  {
           /* Redirect to bank selection
             redirect to bank's login page, 
             do its own checks and process payment. 
             Once successfull, send back to referrer with the payment status
           */
    }

在整个流程中,每个提供者都可以自由询问所需的任何信息(有些只是获取凭据,而另一些则要求提供 OTP 作为附加信息)。他们还根据自己的结构返回状态。然而,在逻辑层面上,如果支付成功与否,他们会获取用户的凭据并返回一条消息

您可以将工厂设计为独立于任何其他供应商设计。只需在每个合同上都有标记接口。

在执行 DI 代码(例如NInject)时,使用“ WhenInjectedInto ”或类似构造将正确的实现注入到正在使用的每个提供程序中。您的工厂将根据用户的选择可供使用,而不会影响您的核心业务流程。

DI的主要规则是从核心业务中完全抽象出非核心业务。核心业务不应该关心每个提供商的期望,只是对预期的功能有一个模糊的想法。标记界面最适合此要求,尤其是当您已经开始设计但还不完全清楚时。随着您对所涉及的过程更加清晰,您可以稍后改进标记界面。

如果您需要进一步了解设计,请告诉我。


推荐阅读