技术开发 频道

ISA总线数据采集卡驱动开发及应用

    1. 问题的提出

开发中,尤其是大型项目的开发中,为了降低模块间、类间的耦合关系,比较提倡基于接口开发,但在实现中也必须面临最终是“谁”提供实体类的问题。Martin Fowler在《Inversion of Control Containers and the Dependency Injection pattern》中也提到了标准的三种实现方式——Constructor Injection、Setter Injection和Interface Injection,很全面的阐释了这个问题。

对于C#而言,由于语法元素上本身要比Java丰富,如何实施注入还有些技巧和特色之处。这方面微软的ObjectBuilder是个不错的教科书,对三种标准方式的实现也都很到位,但就是有些庞大了。

本文中,笔者借鉴Martin Fowler的撰文,也通过一些精简的代码片断向读者介绍C#实现依赖注入的基本技巧。

我有个习惯,每天晚上要看天气预报,就以这个开始好了,先定义待注入对象的抽象行为描述,然后增加一个假的实体类,相关代码和单元测试如下:

C#
using System;
namespace VisionLogic.Training.DependencyInjection.Scenario
{
/// <summary>
/// 抽象注入对象接口
/// </summary>
public interface IWeatherReader
{
string Current { get;}
}
}

C#
using System;
namespace VisionLogic.Training.DependencyInjection.Scenario.Raw
{
/// <summary>
/// 伪造的一个实现类
/// </summary>
class FakeWeatherReader : IWeatherReader
{
public string Current { get { return string.Empty; } }
}

/// <summary>
/// 客户程序
/// </summary>
public class Client
{
protected IWeatherReader reader = new FakeWeatherReader();

public virtual string Weather
{
get
{
string current = reader.Current;
switch (current)
{
case "s": return "sunny";
case "r": return "rainy";
case "c": return "cloudy";
default:
return "unknown";
}
}
}
}
}
Unit Test
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VisionLogic.Training.DependencyInjection.Scenario;
using VisionLogic.Training.DependencyInjection.Scenario.Raw;
namespace VisionLogic.Training.DependencyInjection.Scenario.UnitTest.Raw
{
[TestClass]
public class WeatherReaderTest
{
[TestMethod]
public void Test()
{
Client client = new Client();
Assert.AreEqual<string>("unknown", client.Weather);
}
}
}

    问题就出现了,虽然美好的愿望是Client仅仅依赖抽象的IWeatherReader,但之前总要和一个实体类“轧”一道,那么实际的效果就是实体类作了修改、重新编译了,Client也要处理,没有真正达到隔离的目的。依赖注入通过引入第三方责任者的方法,相对好的梳理了这个关系,这位重要的角色就是一个Assembler类,他和实体类型打交道,对Client而言他总是可以根据约定,加工出需要的IWeatherReader。

0
相关文章