天天看點

單例模式Singleton概述

單例模式屬于建立型模式,它是設計模式中最簡單的一種模式,當然它的使用也是無處不在的。

單例模式保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。

當需要控制一個類的執行個體數量,且調用者可以從一個公共的衆所周知的通路點通路時,我們就可以考慮使用單例模式了。

我們用 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>&lt;?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>?&gt;</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>-&gt;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>-&gt;rndId.</code><code>')&lt;br /&gt;'</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>-&gt;rndId.</code><code>')&lt;br /&gt;'</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>-&gt;whatAmI();</code><code>// should echo 'I am a A(some number)</code>

<code>096</code>

<code>$apple2</code><code>-&gt;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>-&gt;whatAmI();</code><code>// should echo 'I am a A(same number as above)</code>

<code>102</code>

<code>$apple2</code><code>-&gt;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>-&gt;showColor();</code>

<code>37</code>

<code>I am constructed</code>

<code>My Color is Red.</code>

繼續閱讀