許多時(shí)候你想要一個(gè),并且只要一個(gè)類的實(shí)例。比如,你可能需要一個(gè)創(chuàng)建服務(wù)器資源的類,并且你想要保證使用一個(gè)對(duì)象就可以控制這些資源。但是使用時(shí)要小心,因?yàn)閱渭J娇梢院苋菀妆粸E用來模擬不必要的全局變量。
公有類只包含獲得一個(gè)實(shí)例的方法。實(shí)例被保存在該公共對(duì)象的閉包中,并且總是有返回值。
這很奏效因?yàn)?CoffeeScript 允許你在一個(gè)類的聲明中定義可執(zhí)行的狀態(tài)。但是,因?yàn)榇蠖鄶?shù) CoffeeScript 編譯成一個(gè) IIFE 包,如果這個(gè)方式適合你,你就不需要在類的聲明中放置私有的類。之后的內(nèi)容可能對(duì)開發(fā)模塊化代碼有所幫助,例如 CommonJS(Node.js)或 Require.js 中可見(見實(shí)例討論)。
class Singleton
# You can add statements inside the class definition
# which helps establish private scope (due to closures)
# instance is defined as null to force correct scope
instance = null
# Create a private class that we can initialize however
# defined inside this scope to force the use of the
# singleton class.
class PrivateClass
constructor: (@message) ->
echo: -> @message
# This is a static method used to either retrieve the
# instance or create a new one.
@get: (message) ->
instance ?= new PrivateClass(message)
a = Singleton.get "Hello A"
a.echo() # => "Hello A"
b = Singleton.get "Hello B"
b.echo() # => "Hello A"
Singleton.instance # => undefined
a.instance # => undefined
Singleton.PrivateClass # => undefined
通過上面的實(shí)例我們可以看到,所有的實(shí)例是如何從同一個(gè) Singleton 類的實(shí)例中輸出的。你也可以看到,私有類和實(shí)例變量都無法在 Singleton class 外被訪問到。 Singleton class 的本質(zhì)是提供一個(gè)靜態(tài)方法得到只返回一個(gè)私有類的實(shí)例。它也對(duì)外界也隱藏私有類,因此你無法創(chuàng)建一個(gè)自己的私有類。
隱藏或使私有類在內(nèi)部運(yùn)作的想法是更受偏愛的。尤其是由于缺省的 CoffeeScript 將編譯的代碼封裝在自己的 IIFE(閉包)中,你可以定義類而無須擔(dān)心會(huì)被文件外部訪問到。在這個(gè)實(shí)例中,注意,用慣用的模塊導(dǎo)出特點(diǎn)來強(qiáng)調(diào)模塊中可被公共訪問的部分。(請(qǐng)看 “導(dǎo)出到全局命名空間” 中對(duì)此理解更深入的討論)。
root = exports ? this
# Create a private class that we can initialize however
# defined inside the wrapper scope.
class ProtectedClass
constructor: (@message) ->
echo: -> @message
class Singleton
# You can add statements inside the class definition
# which helps establish private scope (due to closures)
# instance is defined as null to force correct scope
instance = null
# This is a static method used to either retrieve the
# instance or create a new one.
@get: (message) ->
instance ?= new ProtectedClass(message)
# Export Singleton as a module
root.Singleton = Singleton
我們可以注意到 coffeescript 是如此簡(jiǎn)單地實(shí)現(xiàn)這個(gè)設(shè)計(jì)模式。為了更好地參考和討論 JavaScript 的實(shí)現(xiàn),請(qǐng)看初學(xué)者必備 JavaScript 設(shè)計(jì)模式。