2

我需要有关 DI 的帮助,但我以前从未使用过 DI。所以概念对我来说是新的。我的问题是假设我需要将日志保存到数据库或平面文件,或者可能是 Windows 事件日志。基于几个参数,我想将日志数据保存到数据库或平面文件或事件日志

例如,如果国家代码是 GBR,那么事件日志将保存到 DB。如果国家代码是美国,那么事件日志将被保存到平面文件中。如果国家代码是美国,那么事件日志将被保存到 Windows 事件日志中。

我得到了一个类似的代码,它用 DI 模式实现了上述问题。这是代码

public interface ILog
{
  void Log(string text);
}

然后在你的类中使用这个接口

public class SomeClass
{
  [Dependency]
  public ILog Log {get;set;}
}

在运行时注入这些依赖项

public class SomeClassFactory
{
  public SomeClass Create()
  {
    var result = new SomeClass();
    DependencyInjector.Inject(result);
    return result;
  }
}

并且实例在 app.config 中配置:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name ="unity"
             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
              Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="singleton"
                 type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" />
    </typeAliases>
    <containers>
      <container>
        <types>
          <type type="MyAssembly.ILog,MyAssembly"
                mapTo="MyImplementations.SqlLog, MyImplementations">
            <lifetime type="singleton"/>
          </type>
        </types>
      </container>
    </containers>
  </unity>
</configuration>

但是上面这段代码的问题是它一次只能做一件事。如果程序集实现存在于 DB 中,那么它将保存到 DB 中,或者如果程序集实现存在于平面文件中,那么它将保存到平面文件中。

但我的要求是相同的,有点不同,比如我想根据国家代码保存数据。所以我需要更改代码和配置文件,因此我可以根据国家/地区代码将数据保存在任何地方。请帮助我的代码和概念。谢谢

4

2 回答 2

3

DI 框架有用的原因是避免需要进行大量样板工厂实现,如下所示:

public class SomeFactory
{
    public SomeClass GetSomeClass()
    {
          return new SomeClass(new SomeDep1(), new SomeDep2(new SomeInnerDep()));
    }
}

如果您在工厂中没有简单的需求,请不要回避只写您需要的东西。在您的示例中:

public class ILogFactory
{
  public ILog Create(CountryCode code)
  {
     if(code == CountryCode.GBR) return new EvenLogger();

     if(code == CountryCode.UK) return new DatabaseLogger(_providerFactory());

     ///etc...
  }
}

编辑:还要注意我写了一个 ILog 工厂而不是 SomeClassFactory。这样,工厂的用户耦合到一个界面,而不是一个具体的实例。这在 DI 中是一个非常有用的实践,通常,因为它允许您替换所需的具体类型。

于 2013-01-10T14:24:57.637 回答
2

你必须做两件事:1)在你的统一容器中注册两个具有特定名称的映射。像这样修改您的 xml 配置:

<type type="MyAssembly.ILog,MyAssembly"
            mapTo="MyImplementations.SqlLog, MyImplementations"
            name="sql">
        <lifetime type="singleton"/>
      </type>
<type type="MyAssembly.ILog,MyAssembly"
            mapTo="MyImplementations.FileLog, MyImplementations"
            name="file">
        <lifetime type="singleton"/>
      </type>

(注意“type”元素的“name”属性)

然后像这样解决您的依赖项(对不起,我不知道 DependencyInjector 类,所以我使用 Unity 容器(Microsoft.Practices.Unity.IUnityContainer):

// create and initialize unity container once somewhere in startup code.
var сontainer = new UnityContainer();
container.LoadConfiguration(); // load unity configuration from application xml config 

// then use container to resolve dependencies.
if (CountryCodeSaysToUseDb())
   return container.Resolve<MyAssembly.ILog>("sql");
if (ContryCodeSaysToUseFile())
   return container.Resolve<MyAssembly.ILog>("file");

但要小心,因为通过在您自己的代码中明确选择特定实现,您正在破坏 DI 模式。

于 2013-01-10T14:46:10.930 回答