我有以下基本界面
public interface IHandler{
void Handle(IMessage message);
}
和继承基本接口的通用接口
public interface IHandler<TMessage> : IHandler where TMessage : IMessage{
void Handle(TMessage message);
}
我的类可以多次实现接口IHandler<TMessage>
。 IMessage
是消息的基本接口,在此处不相关。目前我正在实现如下接口。
public class ExampleHandler : IHandler<ExampleMessage>, IHandler<OtherExampleMessag>{
void IHandler.Handle(IMessage message){
ExampleMessage example = message as ExampleMessage;
if (example != null) {
Handle(example);
}
else {
OtherExampleMessage otherExample = message as OtherExampleMessage;
if (otherExample != null) {
Handle(otherExample);
}
}
public void Handle(ExampleMessage) {
//handle message;
}
public void Handle(OtherExampleMessage) {
//handle message;
}
}
困扰我的是我必须实现Handle(IMessage)
方法的方式,因为在我看来它有很多冗余代码,每次实现新的IHandler<TMessage>
接口时我都必须扩展方法在我的课上。
我正在寻找的是一种更通用的方法来实现Handle(IMessage)
方法(可能在Handlers的基类中),但我目前仍然不知道如何做到这一点。
答案 0 :(得分:3)
您可以使用新的dynamic
关键字将重载决策移至DLR:
void IHandler.Handle(IMessage message)
{
dynamic d = message;
Handle(d);
}
请注意,如果传入的邮件对您的班级无效,则在运行时会因RuntimeBinderException
而失败。
要避免此异常,您可以为所有未知消息类型添加处理程序:
private void Handle(object unknownMessage)
{
// Handle unknown message types here.
}
要在基类中实现IHandler.Handle
,您需要做更多的工作:
public class BaseHandler : IHandler
{
void IHandler.Handle(IMessage message)
{
dynamic d = message;
Handle(d);
}
private void Handle<TMessage>(TMessage message) where TMessage : IMessage
{
var handler = this as IHandler<TMessage>;
if(handler == null)
HandleUnknownMessage(message);
else
handler.Handle(message);
}
protected virtual void HandleUnknownMessage(IMessage unknownMessage)
{
// Handle unknown message types here.
}
}
您的特定处理程序将如下所示:
public class ExampleHandler : BaseHandler,
IHandler<ExampleMessage>,
IHandler<OtherExampleMessage>
{
public void Handle(ExampleMessage message)
{
// handle ExampleMessage here
}
public void Handle(OtherExampleMessage message)
{
// handle OtherExampleMessage here
}
}
此代码现在的工作原理如下:
BaseHandler.Handle<TMessage>
方法,即TMessage
不是IMessage
,而是具体的消息类,如ExampleMessage
。HandleUnknownMessage
来处理未知消息类型。Handle
方法,有效地将调用委托给具体的Handler实现。答案 1 :(得分:1)
合理的方法是明智地使用反思:
var method = this.GetType().GetMethod("Handle", new[] { message.GetType() });
if (method != null) {
method.Invoke(this, new[] { message });
}
如果您这么做以至于性能问题,您可以缓存测试结果以进行大规模改进。
答案 2 :(得分:1)
你因为你的班级(问题中)做了不止一件事而陷入困境。它涉及ExampleMessage
和OtherExampleMessage
。我建议你创建一个类来处理一件事。
示例:强>
public class ExampleHandler : IHandler<ExampleMessage>
和
public class OtherExampleHandler : IHandler<OtherExampleMessag>
根据我的理解,你想要一个类来处理某种事件。在这种情况下,您可能必须使用Observer pattern在发生事件时通知每个处理程序并让他们完成工作。
答案 3 :(得分:-1)
接口说你有一个提供N个服务的实例。当然,服务是相似的,但对于不同的类型,它们是独立的服务。所以你检测到“代码味道”。气味是'为什么不同服务的常用方法?'。
服务的差异是否足以证明通用接口声明的合理性?这里的根本是“重复”。重构重复。复制 BAD 。一旦你移出重复的东西,那么答案将是不言而喻的。
换句话说,摆脱常用方法并用自己的方法处理每个方法......复制就是你要移到另一个类的东西。如果是这样,请考虑注射。
喜欢你的气味检测!