[英]Need to use random number generator in a value type kind of object but don't want the burden of its dependency
我目前有一個名為Gene
的不可變類型,它只有2個字段:
double value;
Interval intervalOfAllowedValues;
我有時需要Gene
將其值隨機切換到其他值,只要它仍然在intervalOfAllowedValues
定義的范圍intervalOfAllowedValues
。
我為此做了一個特殊的方法
public Gene RandomMutation() { ... }
//it returns a Gene because this class is immutable!
使用INumberGenerator.GenerateDouble(...)
來處理這種情況。 問題是RandomMutation()
接受IRandomNumberGenerator
作為參數,然后Gene
必須通過構造函數注入接受一個。
這兩種解決方案都不是我喜歡的:
如果RandomMutation()
通過參數接受數字生成器,則意味着現在不僅Gene
必須知道INumberGenenerator
而且還包含包含它的類。
另一方面,如果我通過構造函數注入一個INumberGenerator
到這個Gene
,大部分時間我都會在那里使用它而不使用它,這看起來不太好。 我覺得它有點失敗了將這個Gene
對象作為值類型存在的目的。 如果它們具有不同的數字生成器,它還提出了2個不同的Gene
是否相等的微妙問題。 如果是,如何進行單元測試?
還有第三種選擇:我將RandomMutation()
從Gene
類中取出。 現在的問題是包含Gene
的類必須知道Gene
和about Interval
,這可能是不可取的。 此外,行為應該接近其數據,並且在遵循此方法時不會出現這種情況。
還有第四種(!)方法:使數字生成器成為全局(Singleton)。 這會產生奇跡,但它違背了使每個依賴都明確的理念。
你怎么處理這種情況?
謝謝
我認為你的第三個選擇肯定是要走的路,不僅是因為可測試性,還因為一般的設計考慮因素。 最后,基因是一種傳遞數據的方式,但它沒有自己的真實行為。 突變只是該數據發生的事情。 因此,RandomMutation生活在其他地方仍然有能力對基因起作用是有意義的。
就可測試性而言,這也是迄今為止最干凈的方法,可以在必要時保持一切明確且易於替換的存根。
我認為有一個GeneMutator類有一個mutate方法接受一個Gene並返回一個mutated Gene(並保留對INumberGenerator的引用),我認為沒有錯。
Interval
似乎很通用,我沒有看到它在Gene
之外可見的缺點。
如果可測試性是您的目標,我喜歡您的第三個選擇。 在數據附近行為是(我的想法)的次要目標,而可測試性和SRP是主要目標。
我的第二個選擇是使用使用構造函數注入將服務放入Gene(或者就此而言是setter注入,盡管我不是粉絲)。 你的主要反對意見似乎是“大多數時候我會把它放在那里而不使用它,這看起來不太好。” 將方法直接放在類上也是如此 - 不同之處在於您只是將該功能移動到注入的類中。
評估在特定Gene
實例的整個生命周期中使用INumberGenerator
類的依賴項的程度並不是一個有用的指標。 僅查看Gene
的定義使用了多少次才有用。 如果它被使用一次,它應該被視為一流的依賴。
更大的問題是擁有一個具有依賴關系的struct
。 RandomMutation
必須有一個INumberGenerator
才能運行,但無論你是使用構造函數還是屬性注入,任何人都可以調用new Gene()
並創建一個具有null依賴項的實例。 您無法強制執行已向struct
提供的依賴項。
你有幾個選擇。 第一種是將Gene
定義為一個class
,它允許您通過構造函數參數將INumberGenerator
聲明為必需的依賴項。 這是面向對象的答案。
您的第二個選擇是使用更具功能性的方法,它將Gene
作為struct
並在外部定義功能。 功能程序傾向於將數據結構與作用於它們的邏輯分開(參見LINQ),而OO則傾向於將行為和數據結合起來。 你的問題聽起來像以這種方式建模最有利。
但是,核心問題仍然存在,即你需要一個Gene
和一個INumberGenerator
才能隨機變異。 由於我們已經確定Gene
可能不應該直接了解INumberGenerator
,因此您可以將其建模為擴展方法:
public static Gene Mutate(this INumberGenerator generator, Gene gene)
{
// ...
}
這INumberGenerator
依賴性從Gene
取出並將其INumberGenerator
到知道何時應該突變基因的對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.