什么是公开API和处理DLL的依赖关系并遵守SOLID的正确方法?

时间:2016-09-09 21:46:24

标签: c# dll dependency-injection solid-principles

揭示可分发DLL的API并处理其依赖关系的最佳方法是什么,考虑到这些依赖关系不应该由客户端处理,而是由DLL本身处理,同时仍然符合SOLID和其他良好做法(可测试等)?

我能想象能够做到这一点的唯一方法是使用普通工厂使用穷人注射公开无参数构造函数,如下所示:

public class MyService
{
    public MyService()
        : this(DependencyFactory.CreateObjectA(), DependencyFactory.CreateObjectB())
    {
    }

    internal MyService(IObjectA objectA, IObjectB objectB)
    {
    }
}

internal static class DependencyFactory
{
    internal static IObjectA CreateObjectA()
    {
        return new ObjectA();
    }

    internal static IObjectB CreateObjectB()
    {
        return new ObjectB();
    }
}

这是正确的道路吗?

2 个答案:

答案 0 :(得分:2)

我建议您为组件保留一个公共构造函数,如下所示:

public class MyService
{
    public MyService(IObjectA objectA, IObjectB objectB)
    {
    }
}

然后创建一个默认工厂,您的库的客户可以使用这样的方便:

public static class MyConvenientFactory
{
    public static MyService CreateDefaultMyService()
    {
        return new MyService(new ObjectA(), new ObjectB());
    }
}

客户会像这样创建你的组件:

var service = MyConvenientFactory.CreateDefaultMyService();

或者更高级的客户端会做这样的事情:

var service =
    new MyService(
        new CachingDecoratorForA(
            new ObjectA()),
        new LoggingDecoratorForB(
            new PerformanceRecorderForB(
                new ObjectB())));

CachingDecoratorForALoggingDecoratorForBPerformanceRecorderForB是由您作为图书馆提供者或客户自己创建的装饰者。

这允许客户端通过不同的组合来自定义组件。这是应用SOLID原则的好处之一。有关对象组合和SOLID的一些讨论,请参阅this article

如果出于任何原因,您不希望这样的高级客户端通过合成自定义组件,那么将构造函数的访问修饰符更改为internal,如下所示:

public class MyService
{
    internal MyService(IObjectA objectA, IObjectB objectB)
    {
    }
}

答案 1 :(得分:1)

为了记录,感谢Yacoub Massad的优秀答案和关于fluent builders的文章,我能够使用Builder模式和Decorator模式以及流畅的API实现构建器。以下是如何使用它:

var myService = MyServiceBuilder
    .Create()
    .WithCachingForA()
    .WithLoggingForB()
    .WithPerformanceRecorderForB()
    .Build();

实施:

public class MyServiceBuilder
{
    private IObjectA ObjectA;
    private IObjectB ObjectB;

    private MyServiceBuilder(IObjectA objectA, IObjectB objectB)
    {
        ObjectA = objectA;
        ObjectB = objectB;
    }

    public static MyServiceBuilder Create()
    {
        return new MyServiceBuilder(new ObjectA(), new ObjectB());
    }

    public MyServiceBuilder WithCachingForA()
    {
        ObjectA = new CachingDecoratorForA(ObjectA);
        return this;
    }

    public MyServiceBuilder WithLoggingForB()
    {
        ObjectB = new LoggingDecoratorForB(ObjectB);
        return this;
    }

    public MyServiceBuilder WithPerformanceRecorderForB()
    {
        ObjectB = new PerformanceRecorderForB(ObjectB);
        return this;
    }

    public MyService Build()
    {
        return new MyService(ObjectA, ObjectB);
    }
}