單例模式屬于建立型模式,它是設計模式中最簡單的一種模式,當然它的使用也是無處不在的。
單例模式保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。
當需要控制一個類的執行個體數量,且調用者可以從一個公共的衆所周知的通路點通路時,我們就可以考慮使用單例模式了。
我們用 UML 來設計單例模式,當然在以後的設計模式的設計部分,我們都将采用 UML 來描述我們的設計,這樣就更為形象化了。
從 UML 設計圖中我們可以看出,為了讓一個類隻有一個執行個體,它必須建立一個靜态變量,然後我們用一個公共靜态的 Instance() 的方法來建立它,但是為了避免這個類自身的構造函數可以建立對象,我們将構造函數設定成 protected 或者 private,這樣外部就隻能通過 Instance() 的方法來建立一個靜态的 Singleton 類。看來這樣我們達到了我們的目的,接下來我們看代碼:
view source
print?
<code>1</code>
<code>public</code> <code>class</code> <code>Singleton {</code>
<code>2</code>
<code> </code><code>private</code> <code>static</code> <code>Singleton instance;</code>
<code>3</code>
<code> </code><code>protected</code> <code>Singleton()</code>
<code>4</code>
<code> </code><code>public</code> <code>static</code> <code>Singleton Instance() {</code>
<code>5</code>
<code> </code><code>if</code><code>(instance !=</code><code>null</code><code>) instance =</code><code>new</code> <code>Singleton();</code>
<code>6</code>
<code> </code><code>return</code> <code>instance;</code>
<code>7</code>
<code> </code><code>}</code>
<code>8</code>
<code>}</code>
由此看來,實作單例模式我們可以做下列幾步:
在類中建立一個靜态變量,變量類型為目前類;
在類中建立一個公共的靜态方法,讓使用者可以通過此方法建立此類的靜态對象;
最後将構造函數設定為 protected 或者 private。
<code>01</code>
<code><?php</code>
<code>02</code>
<code>class</code> <code>Fruit</code>
<code>03</code>
<code>{</code>
<code>04</code>
<code> </code><code>static</code> <code>private</code> <code>$_color</code><code>;</code>
<code>05</code>
<code> </code><code>private</code> <code>function</code> <code>__construct()</code>
<code>06</code>
<code> </code><code>{</code>
<code>07</code>
<code>08</code>
<code> </code>
<code>09</code>
<code> </code><code>static</code> <code>public</code> <code>function</code> <code>singleton() {</code>
<code>10</code>
<code> </code><code>return</code> <code>isset(self::</code><code>$_color</code><code>) ? self::</code><code>$_color</code> <code>: self::</code><code>$_color</code> <code>=</code><code>new</code> <code>self();</code>
<code>11</code>
<code>12</code>
<code>13</code>
<code>?></code>
一個可擴充的單例類看似不可能,但下面的程式很接近這種效果。
<code>001</code>
<code>002</code>
<code>003</code>
<code>class</code> <code>Test</code><code>extends</code> <code>Fruit {</code>
<code>004</code>
<code> </code>
<code>005</code>
<code> </code><code>public</code> <code>static</code> <code>function</code> <code>getInstance()</code>
<code>006</code>
<code>007</code>
<code> </code><code>return</code> <code>Fruit::getSingleton(get_class());</code>
<code>008</code>
<code>009</code>
<code>010</code>
<code>011</code>
<code>012</code>
<code>013</code>
<code>014</code>
<code>class</code> <code>Fruit {</code>
<code>015</code>
<code>016</code>
<code> </code><code>/***********************</code>
<code>017</code>
<code> </code><code>* HOW TO USE</code>
<code>018</code>
<code> </code><code>* </code>
<code>019</code>
<code> </code><code>* Inherit(extend) from Singleton and add getter:</code>
<code>020</code>
<code>021</code>
<code> </code><code>* //public getter for singleton instance</code>
<code>022</code>
<code> </code><code>* public static function getInstance(){</code>
<code>023</code>
<code> </code><code>* return Singleton::getSingleton(get_class());</code>
<code>024</code>
<code> </code><code>* }</code>
<code>025</code>
<code>026</code>
<code> </code><code>*/</code>
<code>027</code>
<code>028</code>
<code> </code><code>private</code> <code>static</code> <code>$instanceMap</code> <code>=</code><code>array</code><code>();</code>
<code>029</code>
<code>030</code>
<code> </code><code>//protected getter for singleton instances</code>
<code>031</code>
<code> </code><code>protected</code> <code>static</code> <code>function</code> <code>getSingleton(</code><code>$className</code><code>)</code>
<code>032</code>
<code>033</code>
<code> </code><code>if</code><code>(!isset(self::</code><code>$instanceMap</code><code>[</code><code>$className</code><code>]))</code>
<code>034</code>
<code> </code><code>{</code>
<code>035</code>
<code> </code>
<code>036</code>
<code> </code><code>$object</code> <code>=</code><code>new</code> <code>$className</code><code>;</code>
<code>037</code>
<code> </code><code>//Make sure this object inherit from Singleton</code>
<code>038</code>
<code> </code><code>if</code><code>(</code><code>$object</code> <code>instanceof Fruit)</code>
<code>039</code>
<code> </code><code>{ </code>
<code>040</code>
<code> </code><code>self::</code><code>$instanceMap</code><code>[</code><code>$className</code><code>] =</code><code>$object</code><code>;</code>
<code>041</code>
<code> </code><code>}</code>
<code>042</code>
<code> </code><code>else</code>
<code>043</code>
<code> </code><code>{</code>
<code>044</code>
<code> </code><code>throw</code> <code>SingletonException(</code><code>"Class '$className' do not inherit from Singleton!"</code><code>);</code>
<code>045</code>
<code>046</code>
<code> </code><code>}</code>
<code>047</code>
<code> </code><code>return</code> <code>self::</code><code>$instanceMap</code><code>[</code><code>$className</code><code>];</code>
<code>048</code>
<code> </code><code>} </code>
<code>049</code>
<code>050</code>
<code> </code><code>//protected constructor to prevent outside instantiation</code>
<code>051</code>
<code> </code><code>protected</code> <code>function</code> <code>__construct(){</code>
<code>052</code>
<code>053</code>
<code>054</code>
<code> </code><code>//denie cloning of singleton objects</code>
<code>055</code>
<code> </code><code>public</code> <code>final</code><code>function</code> <code>__clone(){</code>
<code>056</code>
<code> </code><code>trigger_error(</code><code>'It is impossible to clone singleton'</code><code>, E_USER_ERROR);</code>
<code>057</code>
<code>058</code>
<code>059</code>
<code>060</code>
<code>061</code>
<code>062</code>
<code>class</code> <code>Apple</code><code>extends</code> <code>Fruit {</code>
<code>063</code>
<code>064</code>
<code> </code><code>protected</code> <code>$rndId</code><code>;</code>
<code>065</code>
<code>066</code>
<code>067</code>
<code> </code><code>$this</code><code>->rndId = rand();</code>
<code>068</code>
<code>069</code>
<code>070</code>
<code> </code><code>public</code> <code>function</code> <code>whatAmI(){</code>
<code>071</code>
<code> </code><code>echo</code> <code>'I am a Apple('</code><code>.</code><code>$this</code><code>->rndId.</code><code>')<br />'</code><code>;</code>
<code>072</code>
<code>073</code>
<code>074</code>
<code> </code><code>public</code> <code>static</code> <code>function</code> <code>getInstance(){</code>
<code>075</code>
<code>076</code>
<code>077</code>
<code>078</code>
<code>079</code>
<code>080</code>
<code>class</code> <code>GreenApple</code><code>extends</code> <code>Apple {</code>
<code>081</code>
<code>082</code>
<code>083</code>
<code> </code><code>echo</code> <code>'I am a GreenApple('</code><code>.</code><code>$this</code><code>->rndId.</code><code>')<br />'</code><code>;</code>
<code>084</code>
<code>085</code>
<code>086</code>
<code>087</code>
<code>088</code>
<code>089</code>
<code>090</code>
<code>091</code>
<code>092</code>
<code>$apple1</code> <code>= Apple::getInstance();</code>
<code>093</code>
<code>$apple2</code> <code>= GreenApple::getInstance();</code>
<code>094</code>
<code>095</code>
<code>$apple1</code><code>->whatAmI();</code><code>// should echo 'I am a A(some number)</code>
<code>096</code>
<code>$apple2</code><code>->whatAmI();</code><code>// should echo 'I am a B(some number)</code>
<code>097</code>
<code>098</code>
<code>099</code>
<code>100</code>
<code>101</code>
<code>$apple1</code><code>->whatAmI();</code><code>// should echo 'I am a A(same number as above)</code>
<code>102</code>
<code>$apple2</code><code>->whatAmI();</code><code>// should echo 'I am a B(same number as above)</code>
<code>103</code>
<code>104</code>
<code>// $a = new A();// this should fail</code>
<code>105</code>
<code>// $b = new B();// this should fail</code>
<code>106</code>
<code>107</code>
程式運作結果:
<code>I am a Apple(4462)</code>
<code>I am a GreenApple(8207)</code>
<code> </code>
<code> </code><code>// Hold an instance of the class</code>
<code> </code><code>private</code> <code>static</code> <code>$instance</code><code>;</code>
<code> </code>
<code> </code><code>// A private constructor; prevents direct creation of object</code>
<code> </code><code>protected</code> <code>function</code> <code>__construct()</code>
<code> </code><code>{</code>
<code> </code><code>echo</code> <code>'I am constructed'</code><code>;</code>
<code> </code><code>}</code>
<code>14</code>
<code> </code><code>// The singleton method</code>
<code>15</code>
<code> </code><code>public</code> <code>static</code> <code>function</code> <code>singleton(</code><code>$classname</code> <code>=</code><code>__CLASS__</code><code>)</code>
<code>16</code>
<code>17</code>
<code> </code><code>if</code> <code>(!isset(self::</code><code>$instance</code><code>)) {</code>
<code>18</code>
<code> </code><code>self::</code><code>$instance</code> <code>=</code><code>new</code> <code>$classname</code><code>;</code>
<code>19</code>
<code> </code><code>}</code>
<code>20</code>
<code> </code><code>return</code> <code>self::</code><code>$instance</code><code>;</code>
<code>21</code>
<code>22</code>
<code>23</code>
<code>24</code>
<code>25</code>
<code> </code><code>public</code> <code>static</code> <code>function</code> <code>singleton()</code>
<code>26</code>
<code> </code><code>{</code>
<code>27</code>
<code> </code><code>return</code> <code>parent::singleton(</code><code>__CLASS__</code><code>);</code><code>// NOTE The singleton method MUST return an instance.</code>
<code>28</code>
<code> </code><code>}</code>
<code>29</code>
<code> </code><code>public</code> <code>function</code> <code>showColor()</code>
<code>30</code>
<code>31</code>
<code> </code><code>echo</code> <code>'My Color is Red.'</code><code>;</code>
<code>32</code>
<code>33</code>
<code>34</code>
<code>35</code>
<code>$subclassInstance</code> <code>= Apple::singleton();</code>
<code>36</code>
<code>$subclassInstance</code><code>->showColor();</code>
<code>37</code>
<code>I am constructed</code>
<code>My Color is Red.</code>