首页 > 解决方案 > 正确实现同一接口的正确方法

问题描述

请记住,如果我不需要,我不想添加额外的依赖项。此外,我在寻找解决方案时发现的大部分想法都来自这里(stackoverflow.com)。

假设我有一个 IPrinterRepository 接口,我有多个不同的实现。

例如 EpsonRepository 和 CanonRepository、HPRepository 等一样实现 IPrinterRepository

所以现在我像这样在ConfigurationServices中注册了我的服务

services.AddTransient<EpsonRepository>();
services.AddTransient<HPRepository>();
services.AddSingleton<IPrinterRepositoryResolver, PrinterRepositoryResolver>();

- V1 -

现在,我一直在我的数据库中为每个特定用户激活的每台活动打印机保存一个 PRINTER_CODE。PrinterCode 是一类 const 字符串。

PrinterRepositoryResolver 处理正确实现的选择。所以有一种方法可以使用 switch 语句来做到这一点。

public IPrinterRepository GetRepository(string key)
{   
    switch (key)
    {
        case PrinterCode.Epson:
            return (IPrinterRepository)_serviceProvider.GetService(typeof(EpsonRepository));
        case PrinterCode.HP:
            return (IPrinterRepository)_serviceProvider.GetService(typeof(HPRepository));
        default:
            throw new KeyNotFoundException("Sevice not implemented or not supported any more!");
    }
}

- V2 -

或者也许我可以按类型选择正确的实现,这样我就不必使用 PRINTER_CODE 或维护 switch 语句。例子

而不是 PRINTER_CODE 将 DB 中实现的完整名称保存为字符串,并在以后需要时使用它来选择正确的实现。

public IPrinterRepository GetRepository(string ImplementationName)
{
    var repoType= Type.GetType(ImplementationName);
    return (IPrinterRepository)_serviceProvider.GetService(repoType);
}

这一切都适用于我的开发环境,但我不知道它是否可以。

就个人而言,我不喜欢这个开关,因为每次添加新的打印机实现时,都必须有人维护 PrinterCodes 和开关。

但同时保存一个带有命名空间的长字符串作为选择的键有点难看,我觉得可能还有更多我不知道的缺点。是否有一些调整或更好的想法,所以我可以以正确的方式做到这一点。

标签: c#interfaceasp.net-core-2.0

解决方案


我会采用稍微修改的 V1 方式:

避免了获取样板的对象,并且对象类型与 V2 案例中的名称没有紧密耦合。

public IPrinterRepository GetRepository(string name)
{
    if (!_PrinterTypes.TryGetValue(name, out var type))
        throw new KeyNotFoundException("Sevice not implemented or not supported any more!");

    return _serviceProvider.GetService(type);
}

static readonly Dictionary<string, Type> _PrinterTypes = new Dictionary<string, Type>
{
    [PrinterCode.Epson] = typeof(EpsonRepository),
    [PrinterCode.HP] = typeof(HPRepository)
};

推荐阅读