2

我有 2 个项目:第一个项目是我从 xml 文件中读取的结构项目。
该项目用于其他解决方案第二个项目(其他解决方案中的 1 个)在结构项目上工作,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
    }
}  

现在,如果您熟悉设计模式,那么您可以看到这里有一个注入点,应该执行以下操作:

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 读取数据)。
我想在结构项目(第二个项目)中添加方法和引用(由于多态性)。但是感觉不对,因为使用它的其他项目永远不会使用这些方法和添加的引用。
有没有更好的解决方案来解决这个问题?

编辑:
删除了结构项目代码以缩短问题。这段代码是无关紧要的,因为它的类(组件和 DBComponent)接下来出现。

4

4 回答 4

2

如果您确定要拆分数据结构和数据操作,请创建单独的工作者类。

public interface IWorker
{
    void DoWork();
}

public abstract Worker<T>: IWorker where T: Component
{
     private T _component;
     protected Worker(T component) {_component = component;}
     public abstract void DoWork();
}

public class DbWorker: Worker<DbComponent>
{
     public DbWorker(DbComponent component): base(component) {}
     public override DoWork() {...}
}

并实施一些工厂以从特定组件创建特定工人。

于 2012-09-03T12:19:39.573 回答
2

简单(并具有三种不同的 GOF 设计模式)。

由于我们不能对组件做任何事情,我们将不得不使用桥接模式。

让我们定义处理程序:

public interface IHandlerOf<T> where T : Component
{
    void DoWork(T component);
}

所以现在我们可以为我们想要处理的每个组件类型创建一个处理程序类型。DB 组件处理程序如下所示:

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);
    }
}

请注意,接口 ( 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);

    }
}
于 2012-09-03T12:38:52.783 回答
0

您是否考虑过将解决方案的其他项目打包在一起,以及Operator在第二个项目中?然后,您可以使用 Spring.net 等轻量级容器来配置和加载相关程序集。ComponentDBComponent.exe

于 2012-09-03T12:38:08.210 回答
0

赋予组件行为而不是让工作类操作其属性是正确的做法。

如果您不希望其他项目看到 doWork 方法,请将其隐藏在公共接口后面,并创建一个从公共接口到内部接口的适配器。

public interface ComponentPublic {
    void sharedMethod();
}

public class ComponentPublicAdapter implement ComponentPublic {
    private Component component;
    void sharedMethod() {
        // Do something, may be call doWork()
    }
}

将 ComponentPublic 接口打包在不同的项目/命名空间中,因此其他项目可能会在不知道内部接口的情况下与之交互。使用依赖注入框架或反射来实例化适配器和组件。

于 2012-09-03T12:47:32.197 回答