有更好的设计方案吗
本文关键字:方案 更好 | 更新日期: 2023-09-27 18:30:04
免责声明:我很乐意在此使用依赖项注入项目中,并有一个松散耦合的基于接口的全面设计,但在这个项目中,依赖注入的使用被否决了。此外,在我工作的地方,固体设计原则(以及一般的设计模式)是一种陌生的东西,我自己对其中的许多都是新手。所以考虑一下建议对此问题进行更好的设计时应考虑的问题
这是我正在编写的代码的简化版本,因此它可能看起来有些做作。如果是的话,我道歉。考虑以下类别:
// 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();
然而,我现在发现,在helper.DoSomethingHelpful();
的一些实现中,我还需要执行foo.Operation1
?我想到的潜在解决方案是:
- 使foo和helper具有双向关系。因此,在DoSomethingHelpful中,我们可以调用foo。操作2
- 让foo实现IHelp接口,并将"helper"代码移动到foo中
- 使用委托并将方法Operation2作为
Action<string>
委托传递到Helper的构造函数中
这些方法似乎都不理想(尽管我已经确定我不喜欢选项1,并且如果我们稍后发现需要传递更多委托,我担心选择3的可维护性)。这让我怀疑Helper
/Foo
组合的初始设计是否存在问题。想法?
随意("使用")关系如何:
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,并担心可维护性对于选项3,如果我们稍后发现,我们需要通过更多的代表)。这让我怀疑Helper/Foo组合。"
你说得很对,Helper和Foo的设计有问题。正如您最初描述的那样,基本的Foo/Helper关系很好,当您必须包装其他不受控制的对象时,这是一种常见的模式。但你说:
"如果我发现我也需要在某些情况下执行foo.Operation1helper的实现。DoSomethingHelpful();?"
这就是我们的问题所在。您开始描述Foo依赖Helper的关系;现在您正在描述Helper依赖Foo的关系。这立刻告诉我,你们的依赖关系是纠缠不清的。对象之间的依赖关系应该只朝一个方向发展;事实上,依赖项注入依赖于此。
我认为您已经拥有了所需的东西。尽量不要为"以防万一我以后需要"而设计,也不要修复没有损坏的东西。如果将来需要从助手中使用Operation1,则将其作为对构造函数的依赖项添加(如您所建议的),或者将其传递给您正在调用的方法。这将取决于场景,当你真正需要一些东西时,你就会拥有它。
编辑:更改了"尽量不要为未来设计",因为这似乎不是我想说的。
由于问题发生更改而再次编辑
你可以这样做:
helper.DoSomethingUsefulWith( foo );
因此,您的助手方法将接收到工作所需的依赖项
我认为您的所有解决方案都很好;它们只是提供了不同的功能。这些差异现在并不重要,但在未来很可能会如此。
你更喜欢第二个,你的直觉是最好的指南,你比我们其他人更了解你的代码的未来。我最喜欢你的第二个解决方案,因为它去掉了一个类,更简单。由于它的简单性,如果你以后必须做其他事情,你就不必浪费很多工作。
第一种方法允许您使用不同的Helper(IHelper?)实例和子类玩游戏。最后一种方法为Helper增加了很大的灵活性。(虽然它可能会增加很多内容,但你不需要Helper,只需要你传递给它的方法。)如果其中任何一个似乎能解决未来更多未解决的问题,你可以稍后改用它们。