什么是不透明依赖项?

What are opaque dependencies?

我在阅读有关设计模式的内容时注意到 "opaque dependencies" 一词被广泛使用。 一些消息来源指出:

Opaque dependencies are the bad kind of dependencies

Opaque dependencies are the kind that you can’t assign using a class’s public API.

但是我不是很了解。

有人可以给我一些使用这种依赖关系的例子吗?我为什么要避免使用它们?

例如:

public class MyService
{
    private IRepository repo = new Repository();

    public MyService()
    {
        repo = new Repository();
    }
} 

repo 将被归类为 不透明的依赖关系 因为没有(简单的)方法来改变它,例如在单元测试中。

这是同一个例子,但是作为透明依赖

public class MyService
{
    private IRepository repo = new Repository();

    public MyService(IRepository repositoryDependency)
    {
        repo = repositoryDependency;
    }
} 

这里我们可以传入自己的IRepository并测试MyService的行为,DI Container之类的工具可以为我们设置依赖项,这是它做不到的不透明示例。

不透明的依赖项是隐藏的。不透明依赖的反面是显式依赖。

不透明的依赖关系很糟糕,因为使用 class 的开发人员可能没有意识到这种依赖关系的存在。调用各种方法时可能会出现意想不到的副作用

不透明依赖

public class Users
{
    private Database database;

    public Users()
    {
        this.database = new SqlDatabase(...);
    }

    public User Find(int userId)
    {
        return database.GetById(...);
    }
}

显式依赖

public class Users
{
    private Database database;

    public Users(Database database)
    {
        this.database = database;
    }

    public User Find(int userId)
    {
        return database.GetById(...);
    }
}

基于@NikolaiDante 的回答,我将添加一个论点,即不透明依赖项可以通过透明依赖项引入。

例如:

public class MyService
{
    private ISomeContext context;

    public MyService(ISomeContext context)
    {
        this.context = context;
    }

    public void DoSomethingUseful()
    {
        var repository = this.context.CreateRepository<IRepository>();

        repository.Save(new X());
    }
}

虽然对 ISomeContext 的依赖是透明的,但它隐藏了它用于解析 IRepository 的事实,我现在认为它是不透明的依赖。恕我直言,这减少了 class 设计的 'purity',通常有利于方便或懒惰。

'Digging into Collaborators' 部分 here 中有更多关于此类问题的内容。