簡體   English   中英

需要在值類型對象中使用隨機數生成器,但不希望其依賴性負擔

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM