6

免责声明:我很想在这个项目上使用依赖注入,并且全面采用基于松散耦合接口的设计,但是在这个项目中使用依赖注入已被否决。此外, SOLID设计原则(以及一般的设计模式)在我工作的地方是陌生的,而且我自己对其中的许多人都很陌生。因此,在为这个问题提出更好的设计时要考虑到这一点。

这是我正在处理的代码的简化版本,因此它可能看起来很做作。如果是这样我道歉。考虑以下类:

// Foo is a class that wraps underlying functionality from another 
// assembly to create a simplified API. Think of this as a service layer class,
// a facade-like wrapper. It contains a helper class that is specific to
// foo. Other AbstractFoo implementations have their own helpers.

public class Foo : AbstractFoo
{
    private readonly DefaultHelper helper;
    public override DefaultHelper Helper { get { return helper; } }

    public Foo()
    {
        helper = new Helper("custom stuff");
    }

    public override void Operation1(string value)
    {
        Console.WriteLine("Operation1 using " + value);
    }

    public override void Operation2()
    {
        Console.WriteLine("Operation2");
    }
}

// Helper derives from a default implementation and allows us to
// override it's methods to do things specific for the class that 
// holds this helper. Sometimes we use a custom helper, sometimes
// we use the default one.

public class Helper : DefaultHelper 
{
    private readonly string customStuff;

    public Helper(string value)
    {
        customStuff = value;
    }

    public override void DoSomethingHelpful()
    {
        Console.WriteLine("I was helpful using " + customStuff);
    }
}

假设这两个类的使用如下:

    // foo referenced and used in one part of code
    var foo = new Foo();
    foo.Operation2(); // or foo.Operation1();

    // some other point in the program where we don't have a reference to foo
    // but do have a reference to the helper
    helper.DoSomethingHelpful();

但是我现在发现我还需要foo.Operation1在一些实现中执行helper.DoSomethingHelpful();?我想到的潜在解决方法是:

  1. 让 foo 和 helper 具有双向关系。所以在 DoSomethingHelpful 我们可以调用 foo.Operation2
  2. 让 foo 实现 IHelp 接口并将“帮助”代码移动到 foo
  3. 使用委托并将方法 Operation2 作为Action<string>委托传递给 Helper 的构造函数。

这些方法似乎都不是理想的(尽管我几乎已经确定我不喜欢选项 1 ,并且如果我们稍后发现需要传递更多委托,我担心选项 3的可维护性)。Helper这让我想知道/Foo组合的初始设计是否有问题。想法?

4

4 回答 4

3

随意(“使用”)关系如何:

public class Helper : DefaultHelper 
{
    private readonly string customStuff;

    public Helper(string value)
    {
        customStuff = value;
    }

    public override void DoSomethingHelpful(AbstractFoo foo)
    {
        foo.Operation1();
        Console.WriteLine("I was helpful using " + customStuff);         
    }
}

因此,您修改抽象助手以期望引用正确的Foo实现。

于 2012-04-04T14:45:23.413 回答
1

我想你有你需要的。尽量不要为“以防万一我以后需要它”而设计,不要修复没有损坏的东西。如果将来您需要使用助手中的 Operation1,则将其添加为对构造函数的依赖项(如您所建议的那样),或者将其传递给您正在调用的方法。这将取决于场景,当您真正需要某些东西时,您将拥有它。

编辑:更改了“尽量不要为未来设计”,因为这似乎不是我想说的。

再次编辑由于问题的变化

你可以这样:

helper.DoSomethingUsefulWith( foo );

因此您的辅助方法将收到它需要的依赖项才能工作

于 2012-04-04T14:44:50.533 回答
1

“这些方法似乎都不是理想的(尽管我已经确定我不喜欢选项 1,并且担心选项 3 的可维护性,如果我们稍后发现我们需要传递更多代表)。这让我想知道如果 Helper/Foo 组合的初始设计有问题。”

你完全正确 - Helper 和 Foo 的设计存在问题。您最初描述的基本 Foo/Helper 关系很好,并且当您必须包装其他不受您控制的对象时,这是一种常见模式。但是你说:

“如果我发现我还需要在 helper.DoSomethingHelpful(); 的某些实现中执行 foo.Operation1 怎么办?”

这是我们有问题的地方。您开始描述 Foo 依赖于 Helper 的关系;现在您正在描述 Helper 依赖于 Foo 的关系。这立即告诉我你的依赖关系很纠结。对象之间的依赖关系应该只有一种方式;实际上依赖注入依赖于此。

于 2012-04-04T14:46:01.093 回答
1

我认为您所有的解决方案都很好;它们只是提供不同的功能。这些差异现在无关紧要,但将来可能会如此。

你更喜欢第二个,你的直觉是最好的指导,你比我们其他人更了解你的代码的未来。我最喜欢你的第二个解决方案,因为它摆脱了一个类并且更简单。由于它的简单性,如果您以后必须做其他事情,您将不必丢掉很多工作。

第一种方法让您可以使用不同的 Helper (IHelper?) 实例和子类玩游戏。最后一种方法为 Helper 增加了很大的灵活性。(虽然它可能会增加很多你不需要 Helper 的东西,只是你传递给它的方法。)如果其中任何一个似乎可以解决更多未来未预料到的问题,你可以稍后切换到使用它们。

于 2012-04-04T19:03:02.340 回答