F# 如何实现单例模式(语法)
我有一个从外部源刷新的数据缓存,我想限制我对应用程序内部的缓存(只读)的访问。我不希望每次需要访问数据源时都刷新数据源(例如,在实例化时,获取我需要的所有数据,因为有相当多的数据保持最新) 但是空值的缺乏让我陷入了一个循环。我想我可以使用一个选项类型等,但它是一个循环扔我F# 如何实现单例模式(语法),f#,singleton,F#,Singleton,我有一个从外部源刷新的数据缓存,我想限制我对应用程序内部的缓存(只读)的访问。我不希望每次需要访问数据源时都刷新数据源(例如,在实例化时,获取我需要的所有数据,因为有相当多的数据保持最新) 但是空值的缺乏让我陷入了一个循环。我想我可以使用一个选项类型等,但它是一个循环扔我 type MySingleton = [<DefaultValue>] static val mutable private instance: MySingleton opti
type MySingleton =
[<DefaultValue>]
static val mutable private instance: MySingleton option
static member GetInstance() =
match instance with
| Some(i) -> i
| None ->
*MySingleton.instance = new MySingleton()
MySingleton.instance*
type MySingleton=
[]
静态val可变私有实例:MySingleton选项
静态成员GetInstance()=
匹配实例
|一些(i)->i
|无->
*MySingleton.instance=new MySingleton()
MySingleton.instance*
根据编译器的说法,这种逻辑是错误的
if Helper.notExists MySingleton.instance then
MySingleton.instance <- Some(new MySingleton())
MySingleton.instance
如果Helper.note存在MySingleton.instance,则
MySingleton.instance.NET4.0和F#都有惰性
,所以我认为您需要
module MySingleton =
let private x = Lazy.Create(fun() -> 42)
let GetInstance() = x.Value
(其中,42
可能是一个newwhatevertype()
或任何昂贵的初始化)
(解说:现在是2010年,很少需要显式地处理同步原语;语言和库封装了所有常见模式。)Brian提到的惰性类型是一个很好的起点。它允许您确保在需要该值时运行计算,并保证线程安全,这意味着计算只运行一次(尽管在某些情况下,您也可以使用来指定多个线程可以开始初始化缓存,并且只使用第一个结果)
但是,您可能还需要一种机制来将缓存标记为无效(例如,在指定的时间之后)并强制重新初始化缓存。请注意,这并不是真正的单例模式。无论如何,您仍然可以使用Lazy
以线程安全的方式执行此操作,但您需要像这样构造代码:
module Cache =
// returns a lazy value that initializes the cache when
// accessed for the first time (safely)
let private createCacheInitialization() =
lazy( // some code to calculate cache
cache )
// current cache represented as lazy value
let mutable private currentCache = createCacheInitialization()
// Returns the current cache
let GetCache() = currentCache.Value
// Reset - cache will be re-initialized next time it is accessed
// (this doesn't actually initialize a cache - just creates a lazy value)
let Reset() = currentCache <- createCacheInitialization()
模块缓存=
//返回一个惰性值,该值在
//首次访问(安全)
让private createCacheInitialization()=
lazy(//一些用于计算缓存的代码
缓存)
//当前缓存表示为延迟值
让可变私有currentCache=createCacheInitialization()
//返回当前缓存
让GetCache()=currentCache.Value
//重置-缓存将在下次访问时重新初始化
//(这实际上并没有初始化缓存-只是创建了一个延迟值)
让Reset()=currentCache问题是如何实现单例模式,而不是如何实现延迟加载模式。单个线程可以通过几种方式安全地实现,例如:
// Standard approach in F# 2.0: using an implicit constructor.
type Singleton private() =
static let instance = new Singleton()
static member Instance = instance
// Abbreviated approach in F# 3.0: using an implicit constructor with auto property.
type Singleton private() =
static member val Instance = Singleton()
// Alternative example: When you have to use an explicit ctor,
// and also want to check instanciation upon each access of the property.
/// This type is intended for private use within Singleton only.
type private SyncRoot = class end
type Singleton =
[<DefaultValue>]
static val mutable private instance: Singleton
private new() = { }
static member Instance =
lock typeof<SyncRoot> (fun() ->
if box Singleton.instance = null then
Singleton.instance <- Singleton())
Singleton.instance
//F#2.0中的标准方法:使用隐式构造函数。
类型Singleton private()=
静态let实例=新单例()
静态成员实例=实例
//F#3.0中的简化方法:使用具有auto属性的隐式构造函数。
类型Singleton private()=
静态成员val Instance=Singleton()
//另一个示例:当您必须使用显式ctor时,
//并且还希望在每次访问属性时检查实例。
///此类型仅用于Singleton中的私人使用。
类型private SyncRoot=类结束
类型单态=
[]
静态val可变私有实例:Singleton
private new()={}
静态成员实例=
锁定类型(fun()->
如果box Singleton.instance=null,则
Singleton.instance很抱歉重新提出一个老问题,我只想指出,有些人可能试图在公共属性中公开instance
,在这种情况下,下面的代码可能会很有用:
// private constructor, just as any OO singleton
type public MyType private() =
inherit SomeParent()
static let mutable instance = lazy(new MyType())
// Get the instance of the type
static member Instance with get() = instance.Value
这次是认真的评论。为了确保你在正确的事情上寻求帮助,singleton是一个特殊的精心编制的类,你可以尝试创建任意多的实例,但在第一个实例之后,每次你都会得到第一个实例。因此,如果你尝试创建一个singleton数组,你只会得到一个相同对象的数组通过阅读您的问题,很难判断您是否真的想要这种行为。是的,我想要;singleton将包含大量的数据缓存,并在需要时提供对数据的访问,而不需要每次使用类来刷新/获取数据(这是一个很长的过程)。Lazy.Create(fun()->42)之间有什么区别吗
和lazy(42)
或者它们只是同一事物的不同语法?如果42
是一个构造函数调用,在两个版本中都会延迟吗?同样的事情;lazy(expr)意味着lazy.Create(fun()->expr)@Brian--基本的F#development不是基本上是单例的吗?我是说,认真地说--你赋值一次,然后一遍又一遍地读取该值。我不确定我是否理解这与单例模式之间的区别。@Onorio:单例模式是关于两件事的:让每个人对一个命名对象都有相同的引用(这有点像你所说的),并避免初始化代码产生不良的副作用(可能是实际的副作用,或者只是“性能”效应,例如速度慢,或者占用大量内存或其他资源)。你希望确保这些效应不会发生一次以上(你只需要一个对象),除非需要,否则它们不会发生(如果没有人使用对象,就没有效果)。延迟初始化可以获得这些效果保证。@Brian--好的,我相信我理解你的意思。1.可以将默认构造函数设为私有(如,键入PersonSingleton private()=…
),在这种情况下,您可以在类型中使用static let
。2.不要锁定类型实例;因为该类型是公共的,其他代码也可能锁定它,从而导致死锁。感谢您从未删除
// Standard approach in F# 2.0: using an implicit constructor.
type Singleton private() =
static let instance = new Singleton()
static member Instance = instance
// Abbreviated approach in F# 3.0: using an implicit constructor with auto property.
type Singleton private() =
static member val Instance = Singleton()
// Alternative example: When you have to use an explicit ctor,
// and also want to check instanciation upon each access of the property.
/// This type is intended for private use within Singleton only.
type private SyncRoot = class end
type Singleton =
[<DefaultValue>]
static val mutable private instance: Singleton
private new() = { }
static member Instance =
lock typeof<SyncRoot> (fun() ->
if box Singleton.instance = null then
Singleton.instance <- Singleton())
Singleton.instance
// private constructor, just as any OO singleton
type public MyType private() =
inherit SomeParent()
static let mutable instance = lazy(new MyType())
// Get the instance of the type
static member Instance with get() = instance.Value