我有 2 个项目:第一个项目是一个结构项目,我从 xml 文件中读取它。
该项目已在其他解决方案中使用
第二个项目(其他解决方案之一)处理结构项目,其中 foreach 在组件列表上运行:
namespace FriendProject.Workers
{
public class Worker
{
static void Main(string[] args)
{
foreach (Component component in ComponentList)
{
DoWork(component);
}
}
}
}
现在,DoWork 方法执行以下操作:
public void DoWork(Component component)
{
// Doing work on component properties
// Zip component files with open source Zipper
if (component is DBComponent)
{
// work on DBComponent properties
}
}
现在,如果您熟悉设计模式,那么您可以看到这里有一个注入(inject)点,并且应该执行以下操作:
public class Component
{
public virtual void DoWork()
{
// Do work
}
}
public class DBComponent : Component
{
public override void DoWork()
{
base.DoWork();
// injection point - work on DBComponent properties
}
}
public class Operator
{
static void Main(string[] args)
{
foreach (Component component in ComponentList)
{
component.DoWork();
}
}
}
问题是,保存 Component 和 DBComponent 的项目是一个结构项目,用于其他解决方案和其他项目,我需要将开源 Zip dll 添加到项目中,并且它与当前项目(“FriendProject”)并且不太可用。更不用说其他项目永远不会使用这些方法(Component 和 DBComponent 中的 DoWork)
有没有更好的解决方案而不改变太多设计?我应该添加适配器吗?
如果是,请提供示例。
感谢大家
编辑:简短问题
2个项目:
第一个是一个经理项目,作用于第二个项目。
第二个是一个结构项目(从xml读取数据),它可以与其他项目重用。
我想在结构项目(第二个项目)中添加方法和引用(由于多态性)。然而,这感觉不对,因为使用它的其他项目永远不会使用这些方法和添加的引用。
是否有更好的解决方案如何做到这一点?
编辑:
删除了结构项目代码以缩短问题。这段代码是无关紧要的,因为它的类(Component 和 DBComponent)接下来出现。
最佳答案
简单(并且具有三种不同的 GOF 设计模式)。
由于我们无法对组件执行任何操作,因此我们必须使用桥接模式。
让我们定义处理程序:
public interface IHandlerOf<T> where T : Component
{
void DoWork(T component);
}
现在我们可以为我们想要处理的每个组件类型创建一个处理程序类型。数据库组件处理程序如下所示:
public class DbComponentHandler : IHandlerOf<DbComponent>
{
public void DoWork(DbComponent component)
{
// do db specific information here
}
}
但是由于我们并不真正想要跟踪所有处理程序,因此我们需要创建一个类来为我们完成此操作。我们最终希望像您的示例中那样调用代码:
foreach (Component component in ComponentList)
{
handler.DoWork(component);
}
但是让我们让它变得更酷一点:
//maps handlers to components
var service = new ComponentService();
// register all handlers in the current assembly
service.Register(Assembly.GetExecutingAssembly());
// fake a component
var dbComponent = new DbComponent();
// the cool part, the invoker doesn't have to know
// about the handlers = facade pattern
service.Invoke(dbComponent);
使之成为可能的服务如下所示:
public class ComponentService
{
private readonly Dictionary<Type, IHandlerInvoker> _handlers = new Dictionary<Type, IHandlerInvoker>();
public void Register(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
if (type.IsInterface)
continue;
foreach (var interfaceType in type.GetInterfaces())
{
if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != typeof(IHandlerOf<>))
continue;
var componentType = interfaceType.GetGenericArguments()[0];
var instance = Activator.CreateInstance(type);
var method = instance.GetType().GetMethod("DoWork", new[] { componentType });
_handlers[componentType] = new ReflectionInvoker(instance, method);
}
}
}
public void Register<T>(IHandlerOf<T> handler) where T : Component
{
_handlers[typeof (T)] = new DirectInvoker<T>(handler);
}
#region Nested type: DirectInvoker
private class DirectInvoker<T> : IHandlerInvoker where T : Component
{
private readonly IHandlerOf<T> _handler;
public DirectInvoker(IHandlerOf<T> handler)
{
_handler = handler;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_handler.DoWork((T) component);
}
#endregion
}
#endregion
#region Nested type: IHandlerInvoker
private interface IHandlerInvoker
{
void Invoke(Component component);
}
#endregion
#region Nested type: ReflectionInvoker
private class ReflectionInvoker : IHandlerInvoker
{
private readonly object _instance;
private readonly MethodInfo _method;
public ReflectionInvoker(object instance, MethodInfo method)
{
_instance = instance;
_method = method;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_method.Invoke(_instance, new object[] {component});
}
#endregion
}
#endregion
public void Invoke(Component component)
{
IHandlerInvoker invoker;
if (!_handlers.TryGetValue(component.GetType(), out invoker))
throw new NotSupportedException("Failed to find a handler for " + component.GetType());
invoker.Invoke(component);
}
}
请注意,接口(interface)( IHandlerOf<T>
)是通用的,这意味着我们不能将其直接存储在字典中。因此我们使用适配器模式来存储所有处理程序。
完整示例:
public interface IHandlerOf<in T> where T : Component
{
void DoWork(T component);
}
public class ComponentService
{
private readonly Dictionary<Type, IHandlerInvoker> _handlers = new Dictionary<Type, IHandlerInvoker>();
public void Register(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
if (type.IsInterface)
continue;
foreach (var interfaceType in type.GetInterfaces())
{
if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != typeof(IHandlerOf<>))
continue;
var componentType = interfaceType.GetGenericArguments()[0];
var instance = Activator.CreateInstance(type);
var method = instance.GetType().GetMethod("DoWork", new[] { componentType });
_handlers[componentType] = new ReflectionInvoker(instance, method);
}
}
}
public void Register<T>(IHandlerOf<T> handler) where T : Component
{
_handlers[typeof (T)] = new DirectInvoker<T>(handler);
}
#region Nested type: DirectInvoker
private class DirectInvoker<T> : IHandlerInvoker where T : Component
{
private readonly IHandlerOf<T> _handler;
public DirectInvoker(IHandlerOf<T> handler)
{
_handler = handler;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_handler.DoWork((T) component);
}
#endregion
}
#endregion
#region Nested type: IHandlerInvoker
private interface IHandlerInvoker
{
void Invoke(Component component);
}
#endregion
#region Nested type: ReflectionInvoker
private class ReflectionInvoker : IHandlerInvoker
{
private readonly object _instance;
private readonly MethodInfo _method;
public ReflectionInvoker(object instance, MethodInfo method)
{
_instance = instance;
_method = method;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_method.Invoke(_instance, new object[] {component});
}
#endregion
}
#endregion
public void Invoke(Component component)
{
IHandlerInvoker invoker;
if (!_handlers.TryGetValue(component.GetType(), out invoker))
throw new NotSupportedException("Failed to find a handler for " + component.GetType());
invoker.Invoke(component);
}
}
public class DbComponent : Component
{
}
public class DbComponentHandler : IHandlerOf<DbComponent>
{
public void DoWork(DbComponent component)
{
// do db specific information here
Console.WriteLine("some work done!");
}
}
internal class Program
{
private static void Main(string[] args)
{
var service = new ComponentService();
service.Register(Assembly.GetExecutingAssembly());
var dbComponent = new DbComponent();
service.Invoke(dbComponent);
}
}
关于C# 和设计模式 - 需要一个优雅的解决方案来解决常见问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12247451/