天天看点

java 设计模式 学习笔记(五)单例模式

单例模式:用来创建独一无二的,只能有一个实例的对象的入场券。

   一些对象,我们只需要一个:(线程池,缓存,对话框等等),事实上,这类对象只能有一个实例。如果制造多了了,会导致许多问题,如行为异常、资源使用过量。

   全局变量的缺点,如果将对象赋值给一个全局变量,那么必须在程序一开始就创建好对象,万一这个对象非常消耗资源,而程序在这次的执行过程中又一直没用到它,就形成了浪费。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

<code>public</code> <code>class</code> <code>Singleton {</code>

<code>    </code><code>private</code> <code>static</code> <code>Singleton uniInstance;</code>

<code>    </code><code>public</code> <code>int</code> <code>ID;</code>

<code>                                                                                                                                                                                                                                                                                                                                   </code> 

<code>    </code><code>private</code> <code>Singleton(</code><code>int</code> <code>id) {</code>

<code>        </code><code>ID = id;</code>

<code>    </code><code>}</code>

<code>    </code><code>public</code> <code>static</code> <code>Singleton getInstance(</code><code>int</code> <code>id) {</code>

<code>        </code><code>if</code> <code>(uniInstance == </code><code>null</code><code>) {</code>

<code>            </code><code>uniInstance = </code><code>new</code> <code>Singleton(id);</code>

<code>        </code><code>}</code>

<code>        </code><code>return</code> <code>uniInstance;</code>

<code>}</code>

<code>                                                                                                                                                                                                                                                                                                                                  </code> 

<code>//----------------------Main------------------------</code>

<code>public</code> <code>class</code> <code>Main {</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>

<code>        </code><code>Singleton mSingleton,nSingleton;</code>

<code>        </code><code>mSingleton = Singleton.getInstance(</code><code>3</code><code>);</code>

<code>        </code><code>nSingleton = Singleton.getInstance(</code><code>4</code><code>);</code>

<code>        </code><code>System.out.println(mSingleton.ID);</code>

<code>        </code><code>System.err.println(nSingleton.ID);</code>

   打印出来的结果,都是3,说明mSingleton与nSingleton指向同一对象,保证了实例的唯一性。

请注意,如果不需要这个实例,它就永远不会产生。

   上述为单例模式的经典实现,再看下单例模式的定义:

   确保一个类只有一个实例,并提供一个全局访问点。

   把类设计成自己管理的一个单独实例,同时也避免其他类再自行产生实例。并且提供了这个实例的全局访问点:当你需要实例时,向类查询,它会返回单个实例。

   需要注意的是,Singleton声明的实例对象必须是全局的。假设上述代码中的

<code>Singleton mSingleton,nSingleton;</code>

是分别放在不同线程中声明的,那么getInstance获得的实例就不符合单件模式规则了。

   巧克力工厂:

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

<code>/**</code>

<code> </code><code>* 这是一个巧克力锅炉控制器,锅炉做的事,就是把巧克力和牛奶融在一起, 然后送到下一个阶段,以制造成巧克力棒</code>

<code> </code><code>*/</code>

<code>                                                                  </code> 

<code>public</code> <code>class</code> <code>ChocolateBoiler {</code>

<code>    </code><code>private</code> <code>boolean</code> <code>empty;</code><code>// 代码开始时,锅炉是空的</code>

<code>    </code><code>private</code> <code>boolean</code> <code>boiled;</code>

<code>    </code><code>public</code> <code>ChocolateBoiler() {</code>

<code>        </code><code>empty = </code><code>true</code><code>;</code>

<code>        </code><code>boiled = </code><code>false</code><code>;</code>

<code>    </code><code>/**</code>

<code>     </code><code>* 在锅炉内填入原料时,锅炉必须是空的。 一旦填入原料,就把empty和boiled标志设置好</code>

<code>     </code><code>*/</code>

<code>    </code><code>public</code> <code>void</code> <code>fill() {</code>

<code>        </code><code>if</code> <code>(isEmpty()) {</code>

<code>            </code><code>empty = </code><code>false</code><code>;</code>

<code>            </code><code>boiled = </code><code>true</code><code>;</code>

<code>            </code><code>// 在锅炉内填满巧克力和牛奶的混合物</code>

<code>    </code><code>private</code> <code>boolean</code> <code>isEmpty() {</code>

<code>        </code><code>return</code> <code>empty;</code>

<code>                                                                </code> 

<code>    </code><code>private</code> <code>boolean</code> <code>isBoiled() {</code>

<code>        </code><code>return</code> <code>boiled;</code>

<code>     </code><code>* 锅炉排出时,必须是满的(不可以是空的)而且是煮过的。排出完毕后,把empty标志设回true</code>

<code>    </code><code>public</code> <code>void</code> <code>drain() {</code>

<code>        </code><code>if</code> <code>(!isEmpty() &amp;&amp; isBoiled()) {</code>

<code>            </code><code>// 排除煮沸的巧克力和牛奶</code>

<code>            </code><code>empty = </code><code>true</code><code>;</code>

<code>     </code><code>* 煮混合物时,锅炉必须是满的,并且是没有煮过的,一旦煮沸后,就把boiled标志设为true</code>

<code>    </code><code>public</code> <code>void</code> <code>boil() {</code>

<code>        </code><code>if</code> <code>(!isEmpty() &amp;&amp; !isBoiled()) {</code>

<code>            </code><code>// 将炉内物煮沸</code>

   注意到了,如果同时存在两个以上ChocolateBoiler实例存在,可能会存在的问题:排除500升的为主费的混合物,或者锅炉已经满了还继续放原料,或者锅炉内还没放原料就开始空烧。修改下代码:

<code>    </code><code>private</code> <code>static</code> <code>ChocolateBoiler uniChocolateBoiler;</code>

<code>                                       </code> 

<code>    </code><code>private</code> <code>ChocolateBoiler() {</code>

<code>        </code><code>// TODO Auto-generated constructor stub</code>

<code>    </code><code>public</code> <code>static</code> <code>ChocolateBoiler getInstance() {</code>

<code>        </code><code>if</code> <code>(uniChocolateBoiler == </code><code>null</code><code>) {</code>

<code>            </code><code>uniChocolateBoiler = </code><code>new</code> <code>ChocolateBoiler();</code>

<code>        </code><code>return</code> <code>uniChocolateBoiler;</code>

<code>    </code><code>//后面代码省略</code>

   又遇到了麻烦,fill方法允许在加热的过程中继续假如原料,这可是会溢出五百升的原料。是多线程导致的问题。    

   处理多线程,只要把getInstance()变成同步(synchronized)方法:

<code>class</code> <code>Singleton {</code>

<code>    </code><code>private</code> <code>static</code> <code>Singleton uniqueInstance;</code>

<code>                              </code> 

<code>    </code><code>private</code> <code>Singleton() {</code>

<code>    </code><code>public</code> <code>static</code> <code>synchronized</code> <code>Singleton getInstance() {</code>

<code>        </code><code>if</code> <code>(uniqueInstance == </code><code>null</code><code>) {</code>

<code>            </code><code>uniqueInstance = </code><code>new</code> <code>Singleton();</code>

<code>        </code><code>return</code> <code>uniqueInstance;</code>

综述

   1.单件模式确保程序中一个类最多只有一个实例

   2.单件模式也提供访问这个实例的全局点

   3.在java中实现单件模式需要

   (1)私有构造器

   (2)一个静态方法

   (3)一个静态变量

   4.确定在性能和资源上的限制,然后小心地选择适当的方案来实现单件,以解决多线程的问题

由于最近一直在学习Golang,所以之后学习的设计模式如果没有涉及到Java特有的语言特性,学习笔记中的源码将由Golang来完成

本文转自 ponpon_ 51CTO博客,原文链接:http://blog.51cto.com/liuxp0827/1353917,如需转载请自行联系原作者