与静态方法紧密或松散耦合

Tightly or loose coupled with static methods

public Interface IFoo()
{
    void DoSomething();
}

public class Foo
{
    private IFoo _ifoo;

    public Foo(IFoo foo)
    {
        _ifoo = foo;
    }

    public void Bar()
    {
        // execute
        _ifoo.DoSomething();
    }
}

在上面的例子中——我通过接口使用依赖注入来解耦依赖

VS

在此场景中,class 是否通过使用带有静态方法的 class 紧密耦合?

public class Foo
{
    public static void GenerateSomeFoo(){
        //do something here
    }
}

public class FooBar 
{
    public void Bar()
    {
        var somevariable = 123;
        Foo.GenerateSomeFoo();
    }
}

关于您使用的命名,您造成了误解。有人会期望名为 Foo 的 class 实现接口 IFoo,而不是在 Foo 的构造函数中注入已实现 IFoo 的对象。

就使用静态方法 GenerateSomeFoo 而言,它降低了代码对测试的帮助,因为现在您依赖于 具体 实现。

另一种方法是这样的:

// This is the contract.
public interface IFoo
{
    void DoSomething();
}

// This is the implementation
public class Foo : IFoo
{
    public void DoSomething()
    {
        // ....
    }
}

如果class Foo 需要另一个对象来实现它们的方法,您可以将它注入到它的构造函数中。例如,假设它需要 IBarRepository。然后 class Foo 将声明如下:

public class Foo : IFoo
{
    private readonly IBarRepository _barRepository;

    public Foo(IBarRepository barRepository)
    {
        _barRepository = barRepository 
                         ?? throw new ArgumentNullException(nameof(fooRepository));
    }

    public void DoSomething()
    {
        // ....
    }
}

为什么以上方法更可取?假设 IBarRepository 的定义如下:

public interface IBarRepository
{
    IEnumerable<Bar> GetAll();
}

并且实现此接口的 class 调用数据库以检索 Bar 对象。使用该接口作为依赖项,您可以使用该接口的模拟很容易地测试您的代码,这在您依赖静态 class 或方法时是不可能的。

间接是一个策略问题。拥有战略意味着您至少对未来要做什么有一个遥远的想法。从您的简单示例中,我无法识别任何战略含义。

俗话说"There ain't no problem in the world that can't be solved by another level of indirection"。你可以把它颠倒过来:即使你没有问题,你也可以通过另一个间接级别来解决它......只是因为你身边有一把锤子并不意味着你必须锤击你附近的任何东西。

使用接口来解耦概念当然会有帮助。如果您所做的只是调用一个空方法,它也可能毫无意义。

are the classes tightly coupled by using a class with static methods?

是。

在您的示例中,Foo.GenerateSomeFoo()FooBar class 内部被调用,这使得在需要时更难交换 GenerateSomeFoo() 的实现出于某种原因使用替代实现。因此,FooBar Foo.GenerateSomeFoo() 紧密耦合

静态方法本质上与调用它们的代码紧密耦合,因此您应该避免在静态方法中放置任何可能现在或以后的逻辑未来 接收注入的依赖项。

但是,这并不意味着您永远不应该使用静态方法。扩展方法尤其有用。只是 向它们注入依赖项,它们往往会使测试更加困难。