我有一项任务正在做一些我想要扼杀的后台工作。我想注入void Throttle(taskState)
方法。出于调试目的,它可以像Thread.Sleep(delay)
一样简单,但它可能更复杂,可以进行一些日志记录等。
我在委托和具有单个方法的接口之间进行选择,作为任务驱动类的构造函数的参数。 选择哪个选项?
IMO,就DI而言,接口相对于代理的主要优势是可扩展性。可以轻松添加新方法。我可以创建interface I2: I1 { ... }
,拥有类实现I2
,并仍然将其实例注入I1
。客户端代码可以选择将其强制转换为I2
,以查看是否支持新功能。
但是,如果我只需要注入一个方法,我认为无论是否需要维护状态,委托都会更有意义。代表们也可以保持状态,例如:
static Action<TaskState> GetThrottle(int delay)
{
return (s) => Thread.Sleep(delay++);
}
我明确键入了我的委托,而不是使用Action<>
或Func<>
。
目前,我计划单独使用static
类,其中包含上述各种Throttle
个实现。
我没有在这个项目中使用任何DI框架。
这是正确的选择吗?我应该选择接口吗?
如果您认为答案主要是基于意见的,那么只需投票即可结束这个问题,这也有帮助。
答案 0 :(得分:3)
将接口传递给构造函数的一个好处是它使得依赖解析更容易在DI框架中声明。如果有一个类似的。
public class ClassA{
public ClassA(IInterface interface){
...
}
}
然后使用像Unity这样的DI框架我可以很容易地注册类型
container.RegisterType<IInterface, ConcreteImplementation>();
与代表们的关系变得有点困难。你可能需要做类似的事情。
public class ClassA{
public ClassA(Delegate delegateInstance){
...
}
}
然后注册依赖更加困难。
container.RegisterType<ClassA>(
new InjectionFactory(a => {
return new ClassA(()=>{/*delegate code*/});
}));
答案 1 :(得分:2)
在他的一次演讲中,智者David Chappell曾经说过,如果你面临的设计问题有几种方法可以解决它,你必须在捷径或路径之间做出决定,但有点困难但是提供可扩展性,选择以后。如果需要可扩展性可能会派上用场。如果你是在晚上开车,那么只有你的前灯才能看到。随着你的前进,道路变得越来越清晰。虽然这可能不适用于所有可能的情况,但这个建议对我帮助很大。
在你的情况下,如果我不确定一个代理是我将要用的所有代理,我会通过使用接口来扩展它。
答案 2 :(得分:1)
向界面添加额外方法的能力是一把双刃剑。几个类依赖于接口。一个类需要一些额外的依赖,有人决定将它推入现有的接口(及其实现)。他们不应该,但他们这样做。现在,依赖项有一个额外的方法,其他类不需要,因此违反了接口隔离。另外,依赖它的类正在做更多,但它更难说,因为它的依赖数没有增加。
您可以使用DI容器注册代表。一开始并不漂亮,但有一些扩展方法,没关系。可能存在静态方法适合的情况,并且注册静态方法作为委托的实现非常简单,因为没有类型可以注册或解析,只有委托本身。
以下是使用Autofac的示例:
代表:
public delegate Single DoMath(Single value1, Single value2);
扩展:
public static class AutofacBuilderExtensions
{
public static IRegistrationBuilder<TDelegate, SimpleActivatorData, SingleRegistrationStyle> RegisterDelegate<TDelegate, TSource>(
this ContainerBuilder builder,
Func<TSource, TDelegate> extractDelegate,
string sourceComponentName = null,
string registeredComponentName = null)
where TDelegate : class
{
var registrationFunction = new Func<IComponentContext, TDelegate>(context =>
{
var c = context.Resolve<IComponentContext>();
var source = sourceComponentName == null
? c.Resolve<TSource>()
: c.ResolveNamed<TSource>(sourceComponentName);
return extractDelegate(source);
});
return registeredComponentName == null ?
builder.Register(registrationFunction) :
builder.Register(registrationFunction)
.Named<TDelegate>(registeredComponentName);
}
}
// register the type containing the method so it can be resolved,
// and then register the implementation of the delegate using the extension.
builder.RegisterType<AddsNumbers>();
builder.RegisterDelegate<DoMath, AddsNumbers>(addsNumbers => addsNumbers.DoMath);
或者,如果您只是注册静态实现:
builder.Register<DoMath>(context => MyStaticMathClass.AddsNumbers);