单例模式属于创建型模式,它是设计模式中最简单的一种模式,当然它的使用也是无处不在的。
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
当需要控制一个类的实例数量,且调用者可以从一个公共的众所周知的访问点访问时,我们就可以考虑使用单例模式了。
我们用 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>