2010-02-24 79 views
2

我的任務是維護和更新一個庫,它允許計算機在硬件設備上發送命令,然後接收其響應。目前代碼的設置方式是設備可以接收的每個可能的命令都是通過自己的功能發送的。代碼重複無處不在; DRY倡導者最糟糕的噩夢。如何在不增加其他地方的複雜性的情況下降低庫中的複雜度?

顯然有很多改進的機會。問題是每個命令有不同的有效載荷。目前,要作爲有效載荷的數據以參數的形式傳遞給每個命令函數。如果不將複雜性推到一個稱爲圖書館的水平,就很難合併功能。

當收到來自設備的響應時,其數據被放入一個完全負責保存這些數據的類的對象中,但它們什麼也不做。有數百個這樣做的課程。這些對象隨後用於通過應用層訪問返回的數據。

我的目標:

Throughly減少代碼的重複

維持在應用層

複雜的similiar水平更輕鬆地添加新的命令

我的想法:

有無一個函數發送一個命令,另一個接收函數(接收函數在響應時自動調用檢測到來自設備的電子郵件)。有一個結構體,它保存所有將被傳遞給發送函數並由接收函數返回的命令/響應數據。由於每個命令都有相應的枚舉值,因此需要一個switch語句來設置用於發送的任何命令特定數據。

我的想法是最好的辦法嗎?有我可以在這裏使用的設計模式嗎?我看了看,但看起來並不符合我的需求。

在此先感謝! (如果需要澄清,請讓我知道)

回答

1

那麼,你的問題意味着圖書館的複雜性和客戶之間存在一個平衡點。當這些只有兩種選擇時,幾乎總是會讓客戶的生活更輕鬆。但是,這些並不是真正的唯一選擇。

現在在文中您將討論一個命令處理架構,其中每個命令都有一組與其相關的不同數據。在過去的日子裏,這通常會在循環中用一個大聲的鳴叫case來實現,其中每種情況都稱不同的例程具有不同的參數,並且可能有一些設置代碼。可怕的。 McCabe複雜性分析儀討厭這一點。

這些天你可以用面嚮對象語言做什麼是使用動態調度。用一個標準的「handle()」方法創建一個基本的抽象「命令」類,並讓每個不同的命令從它繼承來添加它們自己的成員(以表示不同命令的不同「參數」)。然後在啓動時創建一個大的喇叭陣列,通常由命令ID進行索引。對於像C++或Ada這樣的語言,它必須是一個指向「命令」對象的指針數組,以便動態分派工作。然後,您可以調用適當的命令對象來獲取從客戶端讀取的命令ID。現在大聲疾呼的case聲明由動態調度隱式處理。

在這種情況下,您可以在這種情況下節省大筆開支。你有幾個使用完全相同參數的命令?爲它們創建一個子類,然後從該子類派生所有這些命令。你有幾個命令必須對其中一個參數執行相同的操作嗎?使用爲該操作實現的一個方法爲它們創建子類,然後從該子類派生所有這些命令。

+0

感謝您的輸入。我絕對同意,無論我最終做什麼,我都不想增加客戶的複雜性。你所描述的古代所用的方法與我所提出的方法很接近。 case語句將用於設置發送到設備的有效負載。 您的設備調度想法是我一直在考慮的事情。我不一定喜歡大喇叭陣列的想法(設置可能很麻煩),但是看起來我最終會得到一個大鳴喇叭的SOMETHING,無論我的方法如何。 – Hojdra 2010-02-24 19:17:13

+0

您實際上可以通過舊式'case'調度方法獲得一些代碼共享...但它涉及到使用goto。這不是大多數人想要(甚至應該)做的事情。 – 2010-02-24 20:02:54

+0

哈哈,不,我寧願不要被迪克斯特拉的鬼魂困擾:)。我一直在想你的建議。正如你所說,我目前的想法是,每個從基類繼承的命令都有一個類。每個類都有一個SendCommand和HandleResponse方法。該類還將封裝發送該命令所需的所有數據以及響應該命令而收到的任何數據。該庫已經使用函數映射來決定在收到響應時要調用哪個響應函數,因此不會有太大的變化。 – Hojdra 2010-02-24 20:14:35

2

這讓我想起了REST vs. SOA的爭論,儘管體型較小。

如果我理解正確的話,現在你有一個像

device->DoThing(); 
device->DoOtherThing(); 

電話,然後有的時候我喜歡

callback->DoneThing(ThingResult&); 
callback->DoneOtherTHing(OtherThingResult&) 

一個回調,我建議用戶是關鍵部件在這裏。目前的圖書館用戶是否喜歡它所設計級別的界面?界面是否一致,即使它很大?

你似乎想提出

device->Do(ThingAndOtherThingParameters&) 
callback->Done(ThingAndOtherThingResult&) 

所以有更復雜的數據單入口點。

從庫用戶角度來看缺點可能現在我不得不使用手動switch()或其他類型的語句來告訴真正發生了什麼。雖然調度到適當的結果回調過去是爲我完成的,但現在你已經使它成爲圖書館用戶的負擔。

除非這給我買了一定程度的靈活性,那我想用戶想要我會考慮這個倒退一步。

對於作爲實現者的部分,一個建議是在內部轉到通用形式,然後在外部提供這兩個接口。也許舊的特定的界面甚至可以以某種方式自動生成。

祝你好運。

+0

謝謝您的輸入。你對我的主張的解釋是正確的。但是,用戶不必處理回調。用戶可以使用「Do」方法將指針傳遞給結構體,然後通過從設備收到響應時調用該方法來填充指針。我的觀點是有人需要向圖書館添加新的命令,並發現目前的體系結構很困難和令人沮喪。不過,我認爲你是正確的,我需要首先考慮用戶的視角。單獨的命令功能更加明確。 – Hojdra 2010-02-24 17:51:54

1

您的第一個目標應該是生成一個將較高軟件層與硬件分離的庫。你的庫的用戶不應該在意你有一個硬件設備可以用不同的有效載荷執行許多功能。他們應該只關心設備在更高級別上的功能。從這個意義上說,我認爲每一個命令都映射到每一個函數是一件好事。

我的計劃是:

  • 確定更高的數據層需要完成工作的對象。從他們的角度而不是從硬件角度對C++類中的對象進行建模
  • 使用上述對象定義庫的接口
  • 開始庫的實現。可能需要將軟件對象映射到硬件對象的中間層
  • 您可以通過很多事情來減少代碼重複。你可以使用多態。定義一個具有基本功能的類並對其進行擴展。您也可以使用實用程序類,實現許多命令所需的功能。
+0

感謝您的輸入。好吧,我想我應該更清楚這一點,這個庫的許多用例包括在某些情況下測試設備,以便用戶需要查看設備是否正確響應命令。在這種情況下,他們確實需要將其視爲執行命令的硬件設備。我完全可以看到將每個命令映射到單獨函數的優點。我喜歡你的中間層的想法。我可能會保留當前可用的接口,並將數據映射到一個新的,組織更好的命令有效負載設置。 – Hojdra 2010-02-24 18:56:11