DLL设计和依赖倒置原则

DLL design and the Dependency Inversion Principle

我有一个有点基本的设计问题,我一直找不到好的答案(在这里,在其他论坛上,也没有我查阅过的书籍)

我正在创建一个 dll,想知道公开其内容的最佳方式是什么。我的目标是为使用 dll 的应用程序提供单一入口点。

解决方案应遵守依赖倒置原则 (DIP),这意味着使用接口。但问题是:dll 的功能需要实例化一个对象,并且在任何时候都必须几乎只有一个实例(有点像单身人士,虽然这个想法让我的脊椎发抖)这就是我想要的事实以免DLL的用户知道。

一些代码来解释我希望能够做什么:

dll:

namespace MyQuestionableDll
{
    interface IMyQuestionableDll
    {
        public static IMyQuestionableDll Instance; // This is not allowed which makes sense
        public void PressTheRedButton();
    }

    internal class QuestionableImplementation : IMyQuestionableDll
    {
        public void PressTheRedButton()
        {
            // Distribute Norwegian Black Metal at local school
        }
    }
}

以及用例:

using MyQuestionableDll;

class UnluckyAppThatIsForcedToUseQuestionableDlls
{
    static void Main(string[] args)
    {
        IMyQuestionableDll questionableInstance = IMyQuestionableDll.Instance; // Again not allowed which still makes sense
        questionableInstance.PressTheRedButton();
        // or simply
        MyQuestionableDll.Instance.PressTheRedButton();
    }
}

摘要 class 可能是答案的一部分,但它开始感觉不再遵循 DIP。

制作 dll 时是否有任何出色的设计见解、最佳实践知识或有关挪威黑金属的建议?

如果解释太含糊,我很乐意详细说明。

干杯! - 雅各布

我可以想象一个 two-factor 方法:

  1. 一个工厂接口(create/return...的一个实例)
  2. API界面

例如:

public interface IMyApiFactory
{
    IMyAPI GetInstance();
}

public interface IMyAPI
{
   // Whatever your API provides
}

这样您就可以在 dll 中完全控制如何创建和重用实例(或不重用实例)。


类似的方式是某种 Builder-Pattern:

public interface IMyApiBuilder
{
    IMyApi Build();
}

public interface IMyApi 
{
   void PressTheRedButton();

   // Whatever it does else
}

public sealed class MyAPI : IMyApi, IMyApiBuilder
{
    public static IMyApiBuilder Builder = new MyAPI();

    private MyAPI() 
    {
        // CTOR ...
    }

    // vv Notice _explicit_ interface implemenations.
    //           https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation

    IMyApi IMyApiBuilder.Build() { return this; }

    void IMyApi.PressTheRedButton()
    {
         // ...
    }
}

// USAGE:

IMyApi api = MyAPI.Builder.Build();

非常感谢 Fildor 和 ema!添加工厂方法、因子接口甚至 full-blown 构建器的想法绝对是不错的解决方案!这让我开始思考如何将它们合并到我的 DLL 中,同时仍然保留其用户。他们不需要知道它实际上是一个散发着污染性烟囱排放物的恶臭工厂 :)

然后我遇到了默认接口方法,我的方法结构最终变成了

public interface MyQuestionableDll
{
    static readonly MyQuestionableDll Instance = new QuestionableImplementation(); 
    void PressTheRedButtonBelowTheDoNotPushSign();
}

internal class QuestionableImplementation : MyQuestionableDll
{
    public void PressTheRedButtonBelowTheDoNotPushSign()
    {
        // Distribute German Volksmusik at local school
    }
}

// and the use case

var questionableInstance = MyQuestionableDll.Instance;
questionableInstance.PressTheRedButtonBelowTheDoNotPushSign();

再次感谢 Fildor 和 ema!

- 雅各布