2012-03-04 62 views
2

我正在研究串行數據協議的解析器。我有一個總體Packet類,一對夫婦的子類,如CommandPacketStatusPacket,然後每個那些幾個子類:TypeOf Subclass的設計模式

    • CommandPacket
      • CommandTypeA
      • CommandTypeB
    • 狀態分組
      • StatusTypeA
      • StatusTypeB

Packet類有用於取數據從一個緩衝器的靜態方法,且如果它表示一個有效的數據包,返回一個新的類實例,用必要的數據實例化。

現在,這是我的問題出現的地方。我希望能夠返回最具體的類型的數據包。爲了促進這一點,我創建了一個靜態的.isValid()方法,該方法在子類上被覆蓋。我的想法是,我可以遍歷每種類型的特定數據包(CommandTypeA,CommandTypeB,StatusTypeA,StatusTypeB等),調用.isValid(),直到其中一個返回TRUE。那時,我會返回一個特定數據包類型的新實例。

當然,我可以直接創建這個方法,我該如何解釋未添加到我的項目中的數據包類型?我希望有人能夠在未來擴展我的班級,而無需修改原始的Packet班級。

我已經考慮過利用反射來實現這個功能,但是我避免了這種情況,因爲這些方法會被調用來接收每個數據包,並且必須高效。

有關如何重新設計我的設計模式的任何想法?


雖然我不認爲這是完全relelvant的討論,我在VB.NET這樣做。還有一個類似的(但不完全相同)的問題發佈在這裏:Java - subclass validation design pattern

+1

如何:創建驗證程序的註冊表,例如'class ValidatorsRegistry:Dictionary > {}'然後註冊每種類型的驗證器。 'validatorsMap.Add(typeof(CommandPacket),IsValidCommandPacket);',並循環你已經做的。 – AVIDeveloper 2012-03-04 22:17:25

+0

@AVIDeveloper,感謝您的建議。我可以在什麼時候將這些類型添加到此字典中?理想情況下,它將在類自身內,但它們不會被實例化。我想我應該創建這個時候我的基類被加載? – Brad 2012-03-04 22:19:59

+0

這就是C++靜態c'tors會很方便的地方。但是,無論如何,您需要在組件的一些常見Init()方法中註冊它們。也許有更好的辦法,但是在這個夜晚的時候就會想到這一點。 – AVIDeveloper 2012-03-04 22:27:06

回答

2

基礎上的意見和MarkJ的帶動下,這裏有一個建議(這是最後一個基於接口,而不是爲更強的類型檢查屬性上):

public interface IPacketValidator 
{ 
    bool IsPacketValid(Packet packet); 
    Type PacketType { get; } 
} 

public class ValidatorsRegistry 
{ 
    private List<IPacketValidator> m_validatorsList; 

    private static ValidatorsRegistry m_Instance = new ValidatorsRegistry(); 
    public static ValidatorsRegistry Instance { get { return m_Instance; } } 

    private ValidatorsRegistry() 
    { 
     InitValidatorsRegistry(); 
    } 

    private void InitValidatorsRegistry() 
    { 
     m_validatorsList = new List<IPacketValidator>(); 

     Type iPacketValidatorType = typeof(IPacketValidator); 

     foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      foreach (Type type in asm.GetTypes()) 
      { 
       if (iPacketValidatorType.IsAssignableFrom(type) && type != iPacketValidatorType) 
       { 
        IPacketValidator validator = (IPacketValidator)Activator.CreateInstance(type); 
        m_validatorsList.Add(validator); 
       } 
      } 
     } 
    } 

    public Type GetSpecificPacketType(Packet packet) 
    { 
     Type packetType = typeof(Packet); 
     foreach (IPacketValidator validator in m_validatorsList) 
     { 
      if (validator.IsPacketValid(packet)) 
      { 
       packetType = validator.PacketType; 
       break; 
      } 
     } 

     return packetType; 
    } 
} 
1

這是一個完美的用例依賴注入容器或MEF我會說。

但回到問題,所以你需要有一個Packet與狀態和一個能力來驗證沒有設置這種狀態。這裏有幾種選擇,都不是完美的:

  1. 讓每個子類的一個實例作爲模板並詢問每個實例是否可以用給定的數據克隆自己。缺點:沒有靜態保證模板不會作爲實際實例傳遞。
  2. 將此邏輯移至單獨的PacketFactory並允許多個工廠(用於可擴展性)。缺點:如果選擇邏輯與分組類型緊密結合,它會創造兩個真相源。
  3. 與當前一樣使用靜態方法,並具有Func<X, Packet>的列表,其中如果X有效,則Func將返回Packet實例,如果不是,則返回null。缺點:沒有靜態保證這個方法被實現。
  4. (只是爲了完整性):與1相同,但創建模板繞過構造函數,以便這種類型的對象在正常情況下不會創建。缺點:破解。

在所有這些情況下,可以使用自定義情況下的反射啓動或選定的DI框架提供的任何擴展機制來完成發現。