2013-03-12 7 views
1

在我的VB.NET程序中,我正在讀取連接到串行端口的設備的命令響應。目前,這個命令集是固定的,但將來可能會添加新的命令。是否有比我可以用來讀取每個命令併爲它們創建對象的巨大開關/ if-then-else語句更優雅的東西?我有一個基本的「命令」類,但每個命令擁有特殊功能的派生類。如何在VB.NET中優雅地創建從串口讀入的命令對象?

我曾希望做出一個優雅的解決方案,避免每次將新對象添加到命令集時更新巨大的switch語句。

回答

4

這取決於你的消息在網上的格式以及你如何反序列化它們。 我會做這樣的事情(例如在C#中,因爲我不使用VB.NET,但它應該很容易轉換)。

每個命令都實現了ICommand接口,並且從某個CommandBase實現類派生。 CommandBase定義了MessageId抽象屬性,它對於每個命令類型都是唯一的(您也可以使用常量)。這個ID也是線路上的消息頭部分的一部分,這樣你就可以知道來自設備的命令。

現在您從設備得到消息ID:

int msgId = ... // what came from the device 
Type cmdType = GetTypeForMessage(msgId); // get the corresponding implementation 
ICommand cmd = (Command)Activator.CreateInstance(cmdType); // crate an instance 
cmd.Deserialize(buffer); // or whatever way you do the serialization 
cmd.Execute(); // run the command 

你從它成立較早的地圖正確的類型:

Type GetTypeForMessage(int msgId) { 
    // m_commandMap is Dictionary<int, Type> 
    return m_commandMap[msgId]; 
} 

現在剩下的問題是如何建立m_commandMap 。一種方法是自動註冊從CommandBase類派生的所有類。你做的啓動是這樣的:

// find all types in this assembly 
    Assembly assembly = Assembly.GetExecutingAssembly(); 
    foreach (var type in assembly.GetTypes()) { 
    if(typeof(CommandBase).IsAssignableFrom(type)) { // which derive from CommandBase 
     CommandBase cmd = (CommandBase) Activator.CreateInstance(type); 
     m_commandMap[cmd.MessageId] = type; 
     // I would make MessageId a static constant on class and read it 
     // using reflection, so I don't have to instantiate an object 
    }      
    } 

現在,當您需要實現新的命令,所有你需要做的就是把它定義:

class NewCommand : CommandBase { 
    public override int MessageId { get { return 1234; } } 
    // or preferably: public const int MessageId = 1234; 
    // the rest of the command: ... 
} 

,會自動註冊在啓動和使用如果相應的ID來自設備,則反序列化。

相關問題