2

2つのプロジェクトがあります。最初のプロジェクトは、xmlファイルから読み取った構造プロジェクトです。
このプロジェクトは他のソリューションで使用されます2番目のプロジェクト(他のソリューションの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プロジェクト:
1つは、2番目のプロジェクトに作用するマネージャープロジェクトです。
2つ目は、他のプロジェクトで再利用される構造プロジェクト(xmlからデータを読み取る)です。
構造体プロジェクト(2番目のプロジェクト)にメソッドと参照(ポリモーフィズム以降)を追加したいと思います。しかし、それを使用する他のプロジェクトはそれらのメソッドと追加された参照を決して使用しないので、それは間違っていると感じます。
それを行う方法についてより良い解決策はありますか?

編集:
構造プロジェクトコードを削除して、質問を短くしました。このコードは、そのクラス(Componentおよび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

簡単(そして3つの異なる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>)は汎用であるため、辞書に直接保存することはできません。したがって、Adapterパターンを使用してすべてのハンドラーを格納します。


完全な例:

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

ソリューションの他のプロジェクトに関して、一緒に、そして2番目のプロジェクトでOperatorパッケージComponent化することを検討しましたか?DBComponent次に、Spring.netなどのライトコンテナを使用して.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 に答える