// 简单用设计模式包裹了一下,工厂+策略,没测试,可以复制到 ide 方便看
public class HandlerKeyAttribute : Attribute
{
public HandlerKeyAttribute(string name)
{
Name = name;
}
public string Name { get; set; }
}
[HandlerKey(nameof(ArgA))]
class ArgA
{
}
[HandlerKey(nameof(ArgB))]
class ArgB
{
}
public class Message
{
public object Param { get; set; }
}
public interface IHandler
{
Task Handle(Message msg);
}
[HandlerKey(nameof(ArgA))]
public class HandlerA : IHandler
{
public Task Handle(Message msg)
{
throw new NotImplementedException();
}
}
[HandlerKey(nameof(ArgB))]
public class HandlerB : IHandler
{
public Task Handle(Message msg)
{
throw new NotImplementedException();
}
}
public class HandlerFactory
{
private static readonly Dictionary<string, Type> _handlerTypes = new();
static HandlerFactory()
{
var handlerTypeInfos = Assembly.GetAssembly(typeof(Program)).DefinedTypes
.Where(x => x.IsClass
&& !x.IsAbstract
&& x.GetInterfaces().Any(i => i == typeof(IHandler)))
.ToList();
foreach (var type in handlerTypeInfos)
{
var attr = type.GetCustomAttribute<HandlerKeyAttribute>();
if (attr != null && !string.IsNullOrEmpty(
attr.Name))
{
try
{
_handlerTypes.Add(
attr.Name, type);
}
catch (Exception)
{
// 当心 key name 重复
}
}
}
}
public IHandler CreateHandler(object arg)
{
//简单用 attribute 匹配 arg 与 handler 类型,具体场景也可以用其他特征(如直接用对象名称)匹配,也可以结合正则、startsWith 等方式匹配
var attr = arg.GetType().GetCustomAttribute<HandlerKeyAttribute>();
if (attr == null || string.IsNullOrEmpty(
attr.Name)) return null;
if (!_handlerTypes.TryGetValue(
attr.Name, out var handlerType))
return null;
// 部分框架里可以利用 ioc container 创建, 如 return _serviceProvider.GetRequiredService(handlerType) as IMqttMessageHandler;
// 部分场景也可以预创建对象,如_handlerTypes 类型改成 Dictionary<string, IHandler> handlers, 直接取拿出来用: return handlers[
attr.name]
return (IHandler)Activator.CreateInstance(handlerType);
}
}
public class Program
{
private static void Main(string[] args)
{
var objects = new List<object> { new ArgA(), new ArgB() };
var factory = new HandlerFactory();
foreach (var arg in objects)
{
var handler= factory.CreateHandler(arg);
handler.Handle(new Message { Param = arg });
}
}
}