2

我有一個RuleTree數據結構,它表示用於處理傳入數據項的規則樹。在規則處理的API中包含可變狀態

  • RuleTree是一個不可變的數據結構,它包含任意數量的(可能嵌套的)規則。
  • 有多個線程將同時將相同的RuleTree應用於不同的輸入數據項
  • RuleTree適用於輸入一個或多個階段的數據。由調用代碼決定應用哪個階段。

典型的控制流程是這樣的:

ruleTree.applyStage1(data); 
.. 
// other stuff happens 
.. 
ruleTree.applyStage2(data); 
.. 
// other stuff happens 
.. 
ruleTree.applyStage3(data); 

這目前工作正常。但是,現在我需要在RuleTree處理期間計算一些額外的狀態信息(例如,計算樹中特定規則的匹配數量)。至於我可以看到它,我有幾個選擇:

  • 充分利用RuleTree可變,使它能夠存儲以後可以回讀狀態信息。這會使併發更加棘手,但是由於不同的線程需要不同的RuleTree副本。
  • 將線程本地狀態添加到RuleTrees - 以便狀態信息可以計算並存儲在RuleTree中,但不同線程不會踐踏彼此的狀態信息。但是這意味着所有階段都必須保證在同一個線程上運行。
  • 爲狀態信息有一個單獨的對象,它可以作爲額外的參數傳遞給ruletree,e.g. ruleTree.applyStage1(data, state)。這使得RuleTree更好且不可變,但是使得它們更加複雜,因爲調用代碼現在必須單獨設置和管理狀態數據。

哪種方法可能是最好的,爲什麼?

回答

2

使用「用於狀態信息的獨立對象」方法,因爲它不會受到您正在考慮的其他方法固有的缺陷的影響。更重要的是,「單獨對象」模型的主要缺陷是,它要求用戶將狀態傳遞給RuleTree的每個方法,可以輕鬆地進行處理。

考慮一下RuleTree的代理。我將使用紅寶石作爲一個可行的近似的僞代碼:

class RuleTreeProxy 

    def initialize(ruleTree) # Constructor 
    @ruleTree = RuleTree 
    @state = RuleTreeState.new 
    end 

    def state 
    return @state 
    end   

    def applyStage1(data) 
    @rule_tree.applyStage1(@state, data) 
    end 

    def applyStage2(data) 
    @rule_tree.applyStage2(@state, data) 
    end 

    # etc. 

end 

@表示對象的成員變量。

任何需要使用RuleTree創建RuleTreeProxy並調用它來代替:

proxy = RuleTreeProxy.new(ruleTree) 
proxy.applyStage1(data) 
proxy.applyStage2(data) 
... 

狀態對象包含訪問器來獲取有關RuleTree完成處理的有用信息:

matches = proxy.state.numberOfMatches 

如果您要求不同的階段可以在不同的線程中完成,那麼要麼確保沒有兩個線程同時嘗試在RuleTreeProxy實例上運行,要麼向RuleTreeProx添加適當的同步年。

+0

感謝您的答案 - 我喜歡使用代理對象系統的想法! – mikera 2012-01-10 08:15:02

+0

@mikera - 感謝您的有趣問題! – 2012-01-10 15:51:41