2015-03-08 64 views
3

我想讓人們對以下方法有所瞭解,甚至建議更好的替代方案。默認爲屬性的訪問者模式

我有一個天氣模擬,我希望能夠隨着模擬的進展計算出特定的屬性。假設我有一個基類WeatherSim,其中從不同類型的模擬派生出來。所以,我可能有一個ConstantTemperatureWeatherSimConstantPressureWeatherSim等。

ConstantTemperatureWeatherSim的情況下,我可能有興趣在如何平均氣壓隨時間的變化(在實際模擬迭代),等等。我也可以運行相同的模擬,我想監視其他屬性,例如平均速度場矢量,或者我想要的任意數量。

事情是,我需要以最有效的方式計算屬性,因爲這些模擬是非常在計算上很昂貴。這意味着雖然我可以有一個向量屬性計算函數,如下所示:

class ConstTempWeatherSim { 
    std::vector<std::function<double(Model&)>> properties; 

    void Iterate() { 
    // Perform calculations... 

    // Calculate properties 
    for(auto& property : properties) 
      property(model); 
} 

這種方法效率很低。對於平均壓力的情況,我可以在模型中循環全部元素並在每次迭代中獲得壓力屬性。更有效的方法是保持平均運行。

問題是,我不想用每一個可能的計算量來污染我的班級(坦率地說,即使我想,我也不能這樣做,因爲我不知道用戶可能想要計算什麼奇怪的屬性)。

我對這個問題的解決方案是使用某種訪問者模式。我的WeatherSimVisitable對象,我想要計算的屬性是我的Visitor。我在我的WeatherSim中存儲了一個Visitors的矢量,每次迭代我都會調用Visitors來完成它們的工作。每位訪客將接受對WeatherSim的引用,因此他們可以在內部存儲他們的運行平均值。

在我看來,這是一個解決這個問題的好方法,除了還有兩件事我需要解決,這就是爲什麼我在這裏。

  1. 某些屬性需要在特定的模擬中執行計算。因此,例如,我可能需要在我的ConstantTempWeatherSim中使用壓力作爲算法的一部分。我是否應該將所需財產的移動平均值與我的Visitors分開保存,並使用它們來增加WeatherSim已計算的財產?或者我應該有一個私人矢量PropertyVisitors,我使用了必要的屬性,並讓用戶將其他所需的任何東西添加到單獨的隊列中?有沒有其他的方法?

  2. 每次迭代後,WeatherSim都會呼叫觀察者記錄所需的信息。將數據從PropertyVisitors轉換爲Observer的最佳方法是什麼?我不認爲將向PropertyVisitors本身的引用向量傳遞給Observers是明智的。我在考慮在我的SimEvent類中包含有關事件的信息,我可以從所有PropertyVisitors中獲取值,並將它們存儲在SimEvent的矢量中。還是我吠叫錯了樹?

也許訪客模式不是最好的方法。我將不勝感激關於如何解決這個問題的想法。

謝謝大家提前!

+0

我不清楚'模型'是什麼?或'WeatherSim'如何與「屬性」相關。我認爲[MCVE](http://stackoverflow.com/help/mcve)會有所幫助。當然,任何MCVE都會大大簡化事情,但我認爲這至少有助於理解你提到的不同對象的角色以及它們之間的相互關係。 – 2015-03-14 13:41:34

+0

您的示例似乎表明「特性」是作爲「WeatherSim」爲特定迭代完成的計算的結果而計算的。但WeatherSim也可能使用一些屬性作爲計算的一部分。那是使用來自以前迭代的屬性嗎?或者是否存在某種依賴關係圖,在計算壓力屬性之前,您無法計算其他內容。 – 2015-03-14 13:56:29

+0

對不起,沒有清晰度。模型僅僅是一個體積的表示,比如說大西洋中部的一個30立方英里的區域。 「WeatherSim」在該捲上運行。所以屬性的思想非常簡單 - 沒有依賴關係圖,所有屬性都只是表示「模型」的特定狀態。例如,如果我想要一個'ConstantTemperature' Sim,那麼它會監測每次迭代的溫度並調整盒子的體積(保持該溫度)。 – pragmatist1 2015-03-14 15:12:59

回答

0

訪客模式在這裏感覺有點奇怪。通常情況下,訪問者需要了解所有可能的可訪問類型。這是如何實現對訪問者類型和可見類型的雙重調度。如果不同的可訪問類型是合理的靜態,但您可能需要在將來添加新的訪問者,這是適合的。在你的情況下,這意味着屬性需要知道所有不同類型的WeatherSim,這聽起來不太合適。我不會期望這種耦合。

但根據我有限的瞭解來回答您的具體問題:

  1. 我建議只有一個屬性列表,但某些屬性可能需要註冊爲特殊性能的一個特定的模擬。特殊屬性的註冊僅存儲對該屬性的引用。然後,用戶可以選擇,例如,他們想要註冊哪個屬性作爲特殊的「壓力」屬性。也許特殊的Pressure屬性需要符合一些「壓力」接口/模板進行註冊。
  2. 通常有兩種方式來運行觀察者推或拉。您可以將一組數據推送給所有觀察者,這是我認爲您通過將值複製到SimEvent而建議的。或者你只是告訴觀察員一些事情已經改變了,觀察者有責任從模擬中提取他們需要的信息。我認爲這兩種方式都是有效的管理方式,哪種方式將取決於您的特定要求。推模型可能效率低下,因爲即使某個特定的Observer可能對某些數據沒有興趣,您也必須推送所有數據。拉模型可能效率低下,因爲通信分兩步完成,Observer可能必須找出哪些數據本身已經發生了變化。拉模型引入了觀察者和模擬之間更多的耦合。在推模式中,您可能必須更改Observer每次需要新內容時推送的一組數據。