有更好的设计选择吗?

时间:2012-04-04 14:28:04

标签: c# oop design-patterns maintainability

  

免责声明:我很乐意在此使用dependency injection   项目并且全面地采用基于接口的松散耦合设计,但在该项目中使用了依赖注入。另外SOLID设计原则(以及design patterns一般而言)是我工作的外国人,我自己也是很多人。所以把它带入   在建议更好地设计这个问题时要考虑。

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

// 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接口并将“helper”代码移动到foo
  3. 使用委托并将方法Operation2作为Action<string>委托传递给Helper的构造函数。
  4. 这些方法似乎都不是理想的(虽然我已经确定我不喜欢选项1 而且如果我们担心选项3 的可维护性稍后发现我们需要传递更多的代表)。这让我想知道Helper / Foo组合的初始设计是否存在问题。想法?

4 个答案:

答案 0 :(得分: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实现。

答案 1 :(得分:1)

我认为你有你需要的东西。尽量不要设计“以防我以后需要它”并且不要修复没有破坏的东西。如果将来你需要从你的帮助器中使用Operation1,然后将它作为构造函数的依赖项(如你所建议的那样)添加,或者只是将它传递给你正在调用的方法。这取决于场景,当你真正需要的时候你就会拥有它。

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

再次编辑问题中的相应更改

你可以这样:

helper.DoSomethingUsefulWith( foo );

所以你的帮助方法将获得工作所需的依赖

答案 2 :(得分:1)

  

“这些方法似乎都不是理想的(虽然我已经很多了   确定我不喜欢选项1,我担心可维护性   如果我们稍后发现我们需要传递更多的代表,则使用选项3)。   这让我想知道初始设计是否存在问题   Helper / Foo组合。“

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

  

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

的实现

这是我们遇到问题的地方。你开始描述Foo依赖于Helper的关系;现在你正在描述Helper依赖于Foo的关系。这立刻告诉我你的依赖关系纠缠不清。对象之间的依赖关系应该只采用一种方式;实际上依赖注入依赖于此。

答案 3 :(得分:1)

我认为你所有的解决方案都很好;他们只是提供不同的能力。这些差异现在不是太重要,但可能在未来。

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

第一种方法允许您使用不同的Helper(IHelper?)实例和子类来玩游戏。最后一种方法为Helper增加了很多灵活性。 (虽然它可能会增加很多,但你不需要帮助,只需要你传递给它的方法。)如果要么解决更多未来的问题,你可以转用它们。问题。