软件设计原则——处理依赖的模式

处理依赖的模式

服务器定位模式

void Copy()
{
    Byte byte;
    var reader = ServiceLocator.GetService<IReader>();
    var writer = ServiceLocator.GetService<IWriter>();

    while (byte == reader.Read())
        writer.Write(byte);
}

使用ServiceLocator返回特定实例,它充当一个工厂。通常的做法是把ServiceLocator创建成一个类,暴露少数静态工厂方法。

public class ServiceLocator
{
    public Object GetService(Type typeToResolve) { ... }
    public T GetService<T>() { ... }
    public Object GetService(string typeNickName) { ... }
}

可以根据参数获取想要的类型

public object GetService(string typeNickName)
{
    if (typeNickName == "sometype")
        return new SomeType();
    if (typeNickName == "someothertype")
        return new SomeOtherType();
}

显然,服务定位器可以采用很复杂的实例化方式(间接创建,对象池,单例),从某个配置文件读取抽象类型和具体类型的映射。

适用场景

最适合它的场景:在一个很难通过其他方式重新设计的某个大型遗留代码,并且需要添加扩展时。

缺点

这个模式的缺点是需要你深入代码才能弄清如何处理依赖。

重要:在多数情况下,服务定位器被看作反模式。理由是你的代码最终会遍布服务定位器类的引用。更糟糕的情况是,直到运行时你才会发现错误。

依赖注入模式

也控制反转或者IOC

void Copy(IReader reader,IWriter writer )
{
    Byte byte;
    while (byte == reader.Read())
        writer.Write(byte);
}

注入依赖有3种方式:使用构造函数、写入属性或者接口。
一般通过构造函数注入,因为这样可以从一开始就清楚表明一个类有什么依赖。基于构造函数的依赖注入也是检测一个类是否“臭”了的绝佳方式。如果发现一个类的构造函数里有20个依赖,很可能这个类没有遵循SRP!

依赖注入的关键是位于这个类之外的工厂代码。但是,这个代码在一些重要的场景里可能是重复的、冗长的。它可能很沉闷,容易出错,极大地抵消了这个模式的好处。有鉴于此,依赖注入通常需要特定的生产力工具,也称为IOC容器。

IOC容器是围绕一个通过某些配置信息解析依赖的容器对象构建的。调用方代码实例化这个容器,并以参数的形式传递想要的接口。作为响应,IOC框架返回一个实现那个接口的具体对象。正确实施依赖注入可能只需直接调用一次IOC容器,所有这些只要几行代码,因为大多数依赖通常会被牵涉的类的构造函数处理。

Microsoft目前提供几个IOC选择。一个是MEF,它主要解决扩展性问题,在客户端应用程序里提供绝佳的插件支持。此外,有MEF2和Unity(unity.codeplex.com)。

Unity和MEF2都可以看作完整的IOC容器。另一方面,MEF只提供IOC容器的基本功能。

猜你喜欢

转载自blog.csdn.net/Star_Inori/article/details/83060555