【发布时间】:2021-03-31 17:29:14
【问题描述】:
Confused about static dictionary in a type, in F# 上的答案以一条建议结束:and just in general: try to use fewer classes and more modules and functions; they're more idiomatic in F# and lead to fewer problems in general
这是一个很好的观点,但是我 30 年的 OO 还不想放弃课程(虽然当我们离开 C 时我正在疯狂地与 C++ 作斗争......)
让我们以一个实际的现实世界对象为例:
type Currency =
{
Ticker: string
Symbol: char
}
and MarginBracket =
{
MinSize: decimal
MaxSize: decimal
Leverage: int
InitialMargin: decimal
MaintenanceMargin: decimal
}
and Instrument =
{
Ticker: string
QuantityTickSize: int
PriceTickSize: int
BaseCurrency: Currency
QuoteCurrency: Currency
MinQuantity: decimal
MaxQuantity: decimal
MaxPriceMultiplier: decimal
MinPriceMultiplier: decimal
MarginBrackets: MarginBracket array
}
// formatting
static member private formatValueNoSign (precision: int) (value: decimal) =
let zeros = String.replicate precision "0"
String.Format($"{{0:#.%s{zeros}}}", value)
static member private formatValueSign (precision: int) (value: decimal) =
let zeros = String.replicate precision "0"
String.Format($"{{0:+#.%s{zeros};-#.%s{zeros}; 0.%s{zeros}}}", value)
member this.BaseSymbol = this.BaseCurrency.Symbol
member this.QuoteSymbol = this.QuoteCurrency.Symbol
member this.QuantityToString (quantity) = $"{this.BaseSymbol}{Instrument.formatValueSign this.QuantityTickSize quantity}"
member this.PriceToString (price) = $"{this.QuoteSymbol}{Instrument.formatValueNoSign this.PriceTickSize price}"
member this.SignedPriceToString (price) = $"{this.QuoteSymbol}{Instrument.formatValueSign this.PriceTickSize price}"
member this.RoundQuantity (quantity: decimal) = Math.Round (quantity, this.QuantityTickSize)
member this.RoundPrice (price : decimal) = Math.Round (price, this.PriceTickSize)
// price deviation allowed from instrument price
member this.LowAllowedPriceDeviation (basePrice: decimal) = this.MinPriceMultiplier * basePrice
member this.HighAllowedPriceDeviation (basePrice: decimal) = this.MaxPriceMultiplier * basePrice
module Instrument =
let private allInstruments = Dictionary<string, Instrument>()
let list () = allInstruments.Values
let register (instrument) = allInstruments.[instrument.Ticker] <- instrument
let exists (ticker: string) = allInstruments.ContainsKey (ticker.ToUpper())
let find (ticker: string) = allInstruments.[ticker.ToUpper()]
在此示例中,有一个 Instrument 对象及其数据和一些帮助器成员,以及一个在需要按名称查找对象时充当存储库的模块(本例中的交易代码)大小写,所以它们是已知的和格式化的,它不是随机字符串)
我可以将帮助成员移动到模块中,例如:
member this.LowAllowedPriceDeviation (basePrice: decimal) = this.MinPriceMultiplier * basePrice
可能变成:
let lowAllowedPriceDeviation basePrice instrument = instrument.MinPriceMultiplier * basePrice
所以对象会变得更简单,最终可以变成简单的存储类型而无需任何扩充。
但我想知道实际的好处是什么(让我们只考虑可读性、可维护性等)?
另外,我不知道如何将其重新构造为不是一个类,在模块中没有一个“内部”类并通过它执行所有操作,但这只会改变它。
【问题讨论】:
-
不需要“和”关键字。在不需要时使用该关键字是不好的做法,因为您向读者暗示存在递归依赖,而实际上没有。这只会让读者不必要地超载。
标签: f#