2012-04-04 66 views
7

免责声明:我喜欢这个 项目中使用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和助手有双向关系。因此,在DoSomethingHelpful我们可以称之为foo.Operation2
  2. 有富实现IHelp界面和移动“帮手”的代码到富
  3. 使用授权,并通过该方法操作2为Action<string>委派到助手的构造函数。

这些方法都没有似乎是理想的(虽然我非常确定我不喜欢选项1和很担心可维护性与选项3如果我们发现以后,我们需要通过在更多的代表)。这让我想知道Helper/Foo组合的初始设计是否有问题。思考?

+0

我想你的意思是'DefaultHelper'而不是'DefualtHelper'。 – ja72 2012-04-04 14:35:15

+0

@ ja72,拼写从来不是我的强项,我更新了这个错字。 – Matt 2012-04-04 14:37:46

+1

+1免责声明...有一个伟大的笑声。 – scottheckel 2012-04-04 14:39:57

回答

1

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

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

“如果我发现,我还需要在helper.DoSomethingHelpful()的一些 实现执行foo.Operation1;”?

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

+0

+1我同意这里,并感谢您确定为什么我不喜欢选项1和3(即纠结的依赖关系)。为什么我认为在这种情况下将Foo和Helper的功能相结合是有意义的,因为它们相互依赖。使用IHelp接口,我仍然可以将Foo视为它是代码中其他位置的Helper。 – Matt 2012-04-05 16:58:23

1

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

编辑:改变了“试图不为未来设计”,因为它似乎并不是我想说的。在这个问题

再次编辑,由于变化

你可以使这样的事情:

helper.DoSomethingUsefulWith(foo); 

所以你的辅助方法,将收到的订单需要依赖工作

+0

尽量不要为未来设计?我明白你想说什么,但总的来说,我不认为这是很好的建议。 – 2012-04-04 14:51:48

+0

设计它可以保持和扩展:是的!添加功能以防万一以后需要:不!这就是我想说的:)。我想我没有为它选择最好的单词嘿嘿 – ivowiblo 2012-04-04 14:53:59

+0

@ivowiblo,我更新了我的问题,因为它不是一个真正的“假设”情况。这是我现在遇到的要求。我应该更清楚。抱歉。 – Matt 2012-04-04 15:15:30

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

在UML中,这是[依赖项](http://publib.boulder.ibm.com/infocenter/rtnlhelp/v6r0m0/index.jsp?topic=%2Fcom.ibm.xtools.modeler.doc%2Ftopics%2Fcdepend。 html)或“使用”关系 – SwDevMan81 2012-04-04 15:01:18

+0

这个问题与Helper具有相同的由AbstractFoo和其他类使用的签名(即AbstractBoo)。如果我将基类更改为接受foo,那么当我使用boo中的helper时,这没有帮助,如果这样做合理的话。可能需要传入Boo(或者可能没有参数)。 – Matt 2012-04-04 15:58:45

+0

@Matt:那么你想让'BooHelper'能够像'FooHelper'获得'Foo'一样使用'Boo'吗?你的评论让我很困惑。 – ja72 2012-04-04 18:21:55

1

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

你更喜欢第二个,你的直觉是这里最好的指南,你比我们其他人更了解你的代码的未来。我喜欢你的第二个解决方案,因为它摆脱了课堂,而且更简单。由于它的简单性,如果你以后需要做其他事情,你不必扔掉很多工作。

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

+0

+1我同意接口的方法,结合Foo和Helper可能是三者中较好的一个,也是我决定采用的方法之一。 – Matt 2012-04-05 16:59:55