2012-09-03 45 views
2

我有2個項目:第一個項目是一個結構項目,我從一個XML文件讀取。
該項目中的其他解決方案 第二個項目(其他的解決方案:1)使用與上組件列表運行的foreach結構項目上工作:C#和設計模式 - 需要一個優雅的解決方案,以解決常見問題

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

問題是,持有組件和DBComponent的項目是一個結構項目,在其他解決方案和其他項目中使用,我需要將開放源代碼Zip dll添加到項目中,並且它變得更緊密地耦合到目前的項目(「FriendProject」)和可用性較差。不談論其他項目將永遠不會使用這些方法(DoWork的在組件和DBComponent)

有沒有太大變化設計一個更好的解決方案?我應該添加一個Adpater嗎?
如果是這樣,請提供例子。
感謝所有

編輯:簡短的問題
2個項目:
一個是項目經理作用於第二個項目。
其次是一個結構項目(從XML讀取數據),可以與其他項目重用。
我想在結構項目(第二個項目)中添加方法和引用(自多態性以來)。然而,它感覺不對,因爲使用它的其他項目將永遠不會使用這些方法和添加的引用。
有沒有更好的解決方案,如何做到這一點?

編輯:
刪除了結構項目代碼縮短了問題。此代碼是無用的,因爲它的類(Component和DBComponent)接下來出現。

+3

有問題的短版嗎?我不確定我在所有這些文本和代碼之間是否有重要的一點。 –

+0

@DanielHilgarth我用一個簡短的問題編輯了這個問題。不過,我在上面添加的細節應該考慮到整個圖片。謝謝 – liorafar

回答

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>)是通用的,這意味着我們不能直接將它存儲在字典中。因此我們使用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); 

    } 
} 
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() {...} 
} 

並實施一些工廠從特定組件創建特定的工人。

0

對於解決方案的其他項目,您是否考慮過在第二個項目中包含OperatorComponentDBComponent?然後,您可以使用輕量級容器(如Spring.net)來配置您的.exe並加載相關的程序集。

0

這是給的而不是工人階級操縱性能的組件的行爲是正確的。

如果您不想讓其他項目看到doWork方法,請將其隱藏在公共接口後面,並從公共接口創建一個適配器到您的內部接口。

public interface ComponentPublic { 
    void sharedMethod(); 
} 

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

包裝在不同的項目/命名空間ComponentPublic接口,所以其他項目可以與它進行交互,而無需知道內部接口。使用依賴注入框架或反射來實例化適配器和組件。