??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品美女www爽爽爽,国产精品一区二区三区成人,日本高清视频一区二区三区http://www.aygfsteel.com/jlin/category/53810.htmlzh-cnSun, 02 Dec 2018 07:59:06 GMTSun, 02 Dec 2018 07:59:06 GMT60在java中写出完的单例模式Q{Q?/title><link>http://www.aygfsteel.com/jlin/archive/2018/11/27/433525.html</link><dc:creator>fly</dc:creator><author>fly</author><pubDate>Tue, 27 Nov 2018 14:51:00 GMT</pubDate><guid>http://www.aygfsteel.com/jlin/archive/2018/11/27/433525.html</guid><wfw:comment>http://www.aygfsteel.com/jlin/comments/433525.html</wfw:comment><comments>http://www.aygfsteel.com/jlin/archive/2018/11/27/433525.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jlin/comments/commentRss/433525.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jlin/services/trackbacks/433525.html</trackback:ping><description><![CDATA[<div class="wmqeeuq" id="cnblogs_post_body" style="margin-bottom: 20px; word-break: break-word;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">1. 前言</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">单例(Singleton)应该是开发者们最熟悉的设计模式了Qƈ且好像也是最Ҏ实现?#8212;—基本上每个开发者都能够随手写出——但是Q真的是q样吗?</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">作ؓ一个Java开发者,也许你觉得自己对单例模式的了解已l够多了。我q不惛_a耸听说一定还有你不知道的——毕竟我自q了解也的有限,但究竟你自己了解的程度到底怎样呢?往下看Q我们一h聊聊看~</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">2. 什么是单例Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">单例对象的类必须保证只有一个实例存?#8212;—q是l基癄上对单例的定义,q也可以作ؓҎ囑֮现单例模式的代码q行验的标准?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">对单例的实现可以分ؓ两大c?#8212;—懒汉式和饿汉式,他们的区别在于:</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><ul style="list-style: none; margin: 0px 0px 10px 30px; padding-left: 0px; font-size: 12px;"><li style="list-style-type: disc;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">懒汉式:指全局的单例实例在W一ơ被使用时构建?/p></li><li style="list-style-type: disc;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">饿汉式:指全局的单例实例在c装载时构徏?/p></li></ul><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">从它们的区别也能看出来,日常我们使用的较多的应该是懒汉式的单例,毕竟按需加蝲才能做到资源的最大化利用嘛~</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3. 懒汉式单?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">先来看一下懒汉式单例的实现方式?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3.1 单版?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">看最单的写法Version 1Q?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Version 1</span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> Single1 { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single1 instance; </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single1 getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { instance </span>= <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> Single1(); } </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> instance; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">或者再q一步,把构造器改ؓU有的,q样能够防止被外部的c调用?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Version 1.1</span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> Single1 { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single1 instance; </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span><span style="line-height: 1.5 !important;"> Single1() {} </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single1 getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { instance </span>= <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> Single1(); } </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> instance; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">我仿佛记得当初学校的教科书就是这么教的?—— 每次获取instance之前先进行判断,如果instance为空new一个出来,否则q接返回已存在的instance?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">q种写法在大多数的时候也是没问题的。问题在于,当多U程工作的时候,如果有多个线E同时运行到if (instance == null)Q都判断为nullQ那么两个线E就各自会创Z个实?#8212;—q样一来,׃是单例了?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3.2 synchronized版本</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">那既然可能会因ؓ多线E导致问题,那么加上一个同步锁吧!</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">修改后的代码如下Q相对于Version1.1Q只是在Ҏ{֐上多加了一个synchronizedQ?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Version 2 </span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> Single2 { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single2 instance; </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span><span style="line-height: 1.5 !important;"> Single2() {} </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span> <span style="color: #0000ff; line-height: 1.5 !important;">synchronized</span><span style="line-height: 1.5 !important;"> Single2 getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { instance </span>= <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> Single2(); } </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> instance; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">OKQ加上synchronized关键字之后,getInstanceҎ׃锁上了。如果有两个U程QT1、T2Q同时执行到q个ҎӞ会有其中一个线ET1获得同步锁,得以l箋执行Q而另一个线ET2则需要等待,当第T1执行完毕getInstance之后Q完成了null判断、对象创建、获得返回g后)QT2U程才会执行执行?#8212;—所以这端代码也避免了Version1中,可能出现因ؓ多线E导致多个实例的情况?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">但是Q这U写法也有一个问题:lgitInstanceҎ加锁Q虽然会避免了可能会出现的多个实例问题,但是会强刉T1之外的所有线E等待,实际上会对程序的执行效率造成负面影响?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3.3 双重查(Double-CheckQ版?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">Version2代码相对于Version1d代码的效率问题,其实是ؓ了解?%几率的问题,而用了一?00%出现的防护盾。那有一个优化的思\Q就是把100%出现的防护盾Q也改ؓ1%的几率出玎ͼ使之只出现在可能会导致多个实例出现的地方?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——有没有这LҎ呢?当然是有的,改进后的代码Vsersion3如下Q?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Version 3 </span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> Single3 { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single3 instance; </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span><span style="line-height: 1.5 !important;"> Single3() {} </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single3 getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { </span><span style="color: #0000ff; line-height: 1.5 !important;">synchronized</span> (Single3.<span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;">) { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { instance </span>= <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> Single3(); } } } </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> instance; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">q个版本的代码看h有点复杂Q注意其中有两次if (instance == null)的判断,q个叫做『双重检?Double-Check』?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><ul style="list-style: none; margin: 0px 0px 10px 30px; padding-left: 0px; font-size: 12px;"><li style="list-style-type: disc;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">W一个if (instance == null)Q其实是Z解决Version2中的效率问题Q只有instance为null的时候,才进入synchronized的代码段——大大减少了几率?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p></li><li style="list-style-type: disc;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">W二个if (instance == null)Q则是跟Version2一P是ؓ了防止可能出现多个实例的情况?/p></li></ul><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">—— q段代码看v来已l完无瑕了?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">—— 当然Q只是『看h』,q是有小概率出现问题的?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">q弄清楚Z么这里可能出现问题,首先Q我们需要弄清楚几个概念Q原子操作、指令重排?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">知识点:什么是原子操作Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">单来_原子操作QatomicQ就是不可分割的操作Q在计算ZQ就是指不会因ؓU程调度被打断的操作?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">比如Q简单的赋值是一个原子操作:</p><div style="margin: 5px 0px; font-size: 12px !important;"><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;">m = 6; <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> q是个原子操?/span></pre></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">假如m原先的gؓ0Q那么对于这个操作,要么执行成功m变成?Q要么是没执行mq是0Q而不会出现诸如m=3q种中间?#8212;—即是在q发的线E中?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">而,声明q赋值就不是一个原子操作:</p><div style="margin: 5px 0px; font-size: 12px !important;"><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #0000ff; line-height: 1.5 !important;">int</span> n = 6; <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> q不是一个原子操?/span></pre></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">对于q个语句Q至有两个操作Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">①声明一个变量n</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">②ln赋gؓ6</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——q样׃有一个中间状态:变量n已经被声明了但是q没有被赋值的状态?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——q样Q在多线E中Q由于线E执行顺序的不确定性,如果两个U程都用mQ就可能会导致不E_的结果出现?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">知识点:什么是指o重排Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">单来_是计算Zؓ了提高执行效率,会做的一些优化,在不影响最l结果的情况下,可能会对一些语句的执行序q行调整?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">比如Q这一D代码:</p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #0000ff; line-height: 1.5 !important;">int</span> a ; <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> 语句1 </span> <span style="line-height: 1.5 !important;"> a </span>= 8 ; <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> 语句2</span> <span style="color: #0000ff; line-height: 1.5 !important;">int</span> b = 9 ; <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> 语句3</span> <span style="color: #0000ff; line-height: 1.5 !important;">int</span> c = a + b ; <span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> 语句4</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">正常来说Q对于顺序结构,执行的顺序是自上CQ也?234?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">但是Q由于指令重排的原因Q因Z影响最l的l果Q所以,实际执行的顺序可能会变成3124或?324?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">׃语句3?没有原子性的问题Q语?和语?也可能会拆分成原子操作,再重排?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——也就是说Q对于非原子性的操作Q在不媄响最l结果的情况下,其拆分成的原子操作可能会被重新排列执行顺序?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">OKQ了解了原子操作和指令重排的概念之后Q我们再l箋看Version3代码的问题?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">下面q段话直接从陈皓的文?深入出单实例SINGLETON设计模式)中复制而来Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">主要在于singleton = new Singleton()q句Q这q是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">1. l?singleton 分配内存</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">2. 调用 Singleton 的构造函数来初始化成员变量,形成实例</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3. singleton对象指向分配的内存空_执行完这?singleton才是?null 了)</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">但是?JVM 的即时编译器中存在指令重排序的优化。也是说上面的W二步和W三步的序是不能保证的Q最l的执行序可能?1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕? 未执行之前,被线E二抢占了,q时 instance 已经是非 null 了(但却没有初始化)Q所以线E二会直接返?instanceQ然后用,然后理成章地报错?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">再稍微解释一下,是_׃有一个『instance已经不ؓnull但是仍没有完成初始化』的中间状态,而这个时候,如果有其他线E刚好运行到W一层if (instance == null)q里Q这里读取到的instance已经不ؓnull了,所以就直接把这个中间状态的instance拿去用了Q就会生问题?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">q里的关键在?#8212;—U程T1对instance的写操作没有完成Q线ET2执行了L作?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3.4 l极版本Qvolatile</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">对于Version3中可能出现的问题Q当然这U概率已l非常小了,但毕竟还是有的嘛~Q,解决Ҏ是:只需要给instance的声明加上volatile关键字即可,Version4版本Q?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Version 4 </span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> Single4 { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span> <span style="color: #0000ff; line-height: 1.5 !important;">volatile</span><span style="line-height: 1.5 !important;"> Single4 instance; </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span><span style="line-height: 1.5 !important;"> Single4() {} </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> Single4 getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { </span><span style="color: #0000ff; line-height: 1.5 !important;">synchronized</span> (Single4.<span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;">) { </span><span style="color: #0000ff; line-height: 1.5 !important;">if</span> (instance == <span style="color: #0000ff; line-height: 1.5 !important;">null</span><span style="line-height: 1.5 !important;">) { instance </span>= <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> Single4(); } } } </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> instance; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">volatile关键字的一个作用是止指o重排Q把instance声明为volatile之后Q对它的写操作就会有一个内存屏障(什么是内存屏障Q)Q这P在它的赋值完成之前,׃用会调用L作?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">注意QvolatileL的不singleton = new Singleton()q句话内部[1-2-3]的指令重排,而是保证了在一个写操作Q[1-2-3]Q完成之前,不会调用L作(if (instance == null)Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——也就d防止了Version3中的问题发生?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——好了Q现在彻底没什么问题了吧?</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">好了Q别紧张Q的没问题了。大名鼎鼎的EventBus中,其入口方法EventBus.getDefault()是用这U方法来实现的?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">不过Q非要挑点刺的话q是能挑出来的,是q个写法有些复杂了,不够优雅、简z?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">4. 饿汉式单?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">下面再聊了解一下饿汉式的单例?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">如上所_饿汉式单例是指:指全局的单例实例在c装载时构徏的实现方式?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">׃c装载的q程是由cd载器QClassLoaderQ来执行的,q个q程也是由JVM来保证同步的Q所以这U方式先天就有一个优?#8212;—能够免疫许多由多U程引v的问题?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">4.1 饿汉式单例的实现方式</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">饿汉式单例的实现如下Q?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;">饿汉式实?/span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> SingleB { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span> <span style="color: #0000ff; line-height: 1.5 !important;">final</span> SingleB INSTANCE = <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> SingleB(); </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span><span style="line-height: 1.5 !important;"> SingleB() {} </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span><span style="line-height: 1.5 !important;"> SingleB getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> INSTANCE; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">对于一个饿汉式单例的写法来_它基本上是完的了?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">所以它的缺点也只是饿汉式单例本n的缺Ҏ在了——׃INSTANCE的初始化是在cd载时q行的,而类的加载是由ClassLoader来做的,所以开发者本来对于它初始化的时机很隑֎准确把握Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><ol style="padding-left: 40px;"><li style="list-style-type: decimal;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">可能׃初始化的太早Q造成资源的浪?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p></li><li style="list-style-type: decimal;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">如果初始化本w依赖于一些其他数据,那么也就很难保证其他数据会在它初始化之前准备好?/p></li></ol><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">当然Q如果所需的单例占用的资源很少Qƈ且也不依赖于其他数据Q那么这U实现方式也是很好的?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">知识点:什么时候是c装载时Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">前面提到了单例在c装载时被实例化Q那I竟什么时候才是『类装蝲时』呢Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">不严格的_大致有这么几个条件会触发一个类被加载:</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">1. new一个对象时</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">2. 使用反射创徏它的实例?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">3. 子类被加载时Q如果父c还没被加蝲Q就先加载父c?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">4. jvm启动时执行的ȝ会首先被加蝲</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">5. 一些其他的实现方式</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">5.1 Effective Java 1 —— 静态内部类</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">《Effective Java》一书的W一版中推荐了一个中写法Q?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Effective Java W一版推荐写?/span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> Singleton { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span> <span style="color: #0000ff; line-height: 1.5 !important;">class</span><span style="line-height: 1.5 !important;"> SingletonHolder { </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span> <span style="color: #0000ff; line-height: 1.5 !important;">final</span> Singleton INSTANCE = <span style="color: #0000ff; line-height: 1.5 !important;">new</span><span style="line-height: 1.5 !important;"> Singleton(); } </span><span style="color: #0000ff; line-height: 1.5 !important;">private</span><span style="line-height: 1.5 !important;"> Singleton (){} </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">static</span> <span style="color: #0000ff; line-height: 1.5 !important;">final</span><span style="line-height: 1.5 !important;"> Singleton getInstance() { </span><span style="color: #0000ff; line-height: 1.5 !important;">return</span><span style="line-height: 1.5 !important;"> SingletonHolder.INSTANCE; } }</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">q种写法非常巧妙Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><ul style="list-style: none; margin: 0px 0px 10px 30px; padding-left: 0px; font-size: 12px;"><li style="list-style-type: disc;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">对于内部cSingletonHolderQ它是一个饿汉式的单例实玎ͼ在SingletonHolder初始化的时候会由ClassLoader来保证同步,使INSTANCE是一个真·单例?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p></li><li style="list-style-type: disc;"><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">同时Q由于SingletonHolder是一个内部类Q只在外部类的Singleton的getInstance()中被使用Q所以它被加载的时机也就是在getInstance()ҎW一ơ被调用的时候?/p></li></ul><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">——它利用了ClassLoader来保证了同步Q同时又能让开发者控制类加蝲的时机。从内部看是一个饿汉式的单例,但是从外部看来,又的是懒汉式的实现?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">直是乎其技?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">5.2 Effective Java 2 —— 枚D</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">你以为到q就完了?不,q没有,因ؓ厉害的大又发现了其他的Ҏ?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">《Effective Java》的作者在q本书的W二版又推荐了另外一U方法,来直接看代码Q?/p><div style="margin: 5px 0px; font-size: 12px !important;"><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important;"><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> Effective Java W二版推荐写?/span> <span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">enum</span><span style="line-height: 1.5 !important;"> SingleInstance { INSTANCE; </span><span style="color: #0000ff; line-height: 1.5 !important;">public</span> <span style="color: #0000ff; line-height: 1.5 !important;">void</span><span style="line-height: 1.5 !important;"> fun1() { </span><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> do something</span> <span style="line-height: 1.5 !important;"> } } </span><span style="color: #008000; line-height: 1.5 !important;">//</span><span style="color: #008000; line-height: 1.5 !important;"> 使用</span> <span style="line-height: 1.5 !important;"> SingleInstance.INSTANCE.fun1();</span></pre><div style="margin-top: 5px;"><span style="padding-right: 5px; line-height: 1.5 !important;"><a title="复制代码" style="color: #1a8bc8; border: none !important;"><img src="https://common.cnblogs.com/images/copycode.gif" alt="复制代码" style="max-width: 900px; height: auto; border: none !important;" /></a></span></div></div><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">看到了么Q这是一个枚丄?#8230;…qclass都不用了Q极?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">׃创徏枚D实例的过E是U程安全的,所以这U写法也没有同步的问题?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">作者对q个Ҏ的评P</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">q种写法在功能上与共有域Ҏ相近Q但是它更简z,无偿地提供了序列化机Ӟl对防止Ҏ实例化,即是在面对复杂的序列化或者反攻ȝ时候。虽然这中方法还没有q泛采用Q但是单元素的枚丄型已l成为实现Singleton的最x法?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">枚D单例q种Ҏ问世一些,许多分析文章都称它是实现单例的最完美Ҏ——写法񔽎单,而且又能解决大部分的问题?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">不过我个U方法虽然很优秀Q但是它仍然不是完美?#8212;—比如Q在需要承的场景Q它׃适用了?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">6. ȝ</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">OKQ看到这里,你还会觉得单例模式是最单的设计模式了么Q再回头看一下你之前代码中的单例实现Q觉得是无懈可击的么Q?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">可能我们在实际的开发中Q对单例的实现ƈ没有那么严格的要求。比如,我如果能保证所有的getInstance都是在一个线E的话,那其实第一U最单的教科书方式就够用了。再比如Q有时候,我的单例变成了多例也可能对程序没什么太大媄?#8230;…</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">但是Q如果我们能了解更多其中的细节,那么如果哪天E序Z些问题,我们L能多一个排查问题的炏V早点解决问题,p早点回家吃饭……</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">—— q有Q完的Ҏ是不存在QQ何方式都会有一个『度』的问题。比如,你的觉得代码已经无懈可击了,但是因ؓ你用的是JAVA语言Q可能ClassLoader有些BUG?#8230;…你的代码谁运行在JVM上的Q可能JVM本n有BUG?#8230;…你的代码q行在手ZQ可能手机系l有问题?#8230;…你生zdq个宇宙里,可能宇宙本n有些BUG?#8230;…</p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">所以,力做到能做到的最好就行了?/p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;"> </p><p style="line-height: 1.5; margin-top: 10px; margin-bottom: 10px;">—— 感谢你花费了不少旉看到q里Q但愿你没有觉得虚度?/p></div><div style="clear: both;"></div><div class="wmqeeuq" id="blog_post_info_block" style="margin-top: 20px;"><div class="wmqeeuq" id="BlogPostCategory" style="margin-bottom: 10px; color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #ffffff;"></div><div class="wmqeeuq" id="EntryTag" style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #ffffff; margin-top: 0px !important;"></div><div class="wmqeeuq" id="blog_post_info" style="color: #4b4b4b; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #ffffff;"></div></div><img src ="http://www.aygfsteel.com/jlin/aggbug/433525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jlin/" target="_blank">fly</a> 2018-11-27 22:51 <a href="http://www.aygfsteel.com/jlin/archive/2018/11/27/433525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Java 中的双重查(Double-Check)-?/title><link>http://www.aygfsteel.com/jlin/archive/2017/06/06/432584.html</link><dc:creator>fly</dc:creator><author>fly</author><pubDate>Tue, 06 Jun 2017 05:36:00 GMT</pubDate><guid>http://www.aygfsteel.com/jlin/archive/2017/06/06/432584.html</guid><wfw:comment>http://www.aygfsteel.com/jlin/comments/432584.html</wfw:comment><comments>http://www.aygfsteel.com/jlin/archive/2017/06/06/432584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jlin/comments/commentRss/432584.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jlin/services/trackbacks/432584.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; background-color: #ffffff;">?Effecitve <a title="Java 知识? target="_blank" style="color: #df3434; text-decoration-line: none; font-weight: bold;">Java</a> 一书的W?48 条中提到了双重检查模式,q指U模式在 Java 中通常q不适用。该模式的结构如下所C:</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"></p><div bg_java"="" style="width: 700.906px; overflow-y: hidden; position: relative;"><div><div><strong>[java]</strong> <a title="view plain" target="_blank" style="background-image: url("images/default/ico_plain.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">view plain</a><span data-mod="popu_168"> <a title="copy" target="_blank" style="background-image: url("images/default/ico_copy.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">copy</a><div style="position: absolute; left: 563px; top: 634px; width: 18px; height: 18px; z-index: 99;"></div></span></div></div><ol start="1"><li style="line-height: 18px;">public Resource getResource() {  </li><li style="line-height: 18px;">  if (resource == null) {   </li><li style="line-height: 18px;">    synchronized(this){   </li><li style="line-height: 18px;">      if (resource==null) {  </li><li style="line-height: 18px;">        resource = new Resource();    </li><li style="line-height: 18px;">      }     </li><li style="line-height: 18px;">    }    </li><li style="line-height: 18px;">  }  </li><li style="line-height: 18px;">  return resource;  </li><li style="line-height: 18px;">}  </li></ol></div><p> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">该模式是对下面的代码改进Q?/p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"></p><div bg_java"="" style="width: 700.906px; overflow-y: hidden; position: relative;"><div><div><strong>[java]</strong> <a title="view plain" target="_blank" style="background-image: url("images/default/ico_plain.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">view plain</a><span data-mod="popu_168"> <a title="copy" target="_blank" style="background-image: url("images/default/ico_copy.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">copy</a><div style="position: absolute; left: 563px; top: 949px; width: 18px; height: 18px; z-index: 99;"></div></span></div></div><ol start="1"><li style="line-height: 18px;">public synchronized Resource getResource(){  </li><li style="line-height: 18px;">  if (resource == null){   </li><li style="line-height: 18px;">        resource = new Resource();    </li><li style="line-height: 18px;">  }  </li><li style="line-height: 18px;">  return resource;  </li><li style="line-height: 18px;">}  </li></ol></div><p> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">q段代码的目的是?resource 延迟初始化。但是每ơ访问的时候都需要同步。ؓ了减同步的开销Q于是有了双重检查模式?/p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">?Java 中双重检查模式无效的原因是在不同步的情况下引用类型不是线E安全的。对于除?long ?double 的基本类型,双重查模式是适用 的。比如下面这D代码就是正的Q?/p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"></p><div bg_java"="" style="width: 700.906px; overflow-y: hidden; position: relative;"><div><div><strong>[java]</strong> <a title="view plain" target="_blank" style="background-image: url("images/default/ico_plain.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">view plain</a><span data-mod="popu_168"> <a title="copy" target="_blank" style="background-image: url("images/default/ico_copy.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">copy</a><div style="position: absolute; left: 563px; top: 1284px; width: 18px; height: 18px; z-index: 99;"></div></span></div></div><ol start="1"><li style="line-height: 18px;">private int count;  </li><li style="line-height: 18px;">public int getCount(){  </li><li style="line-height: 18px;">  if (count == <span style="color: #c00000;">0</span>){   </li><li style="line-height: 18px;">    synchronized(this){   </li><li style="line-height: 18px;">      if (count == <span style="color: #c00000;">0</span>){  </li><li style="line-height: 18px;">        count = computeCount();  //一个耗时的计?nbsp; </li><li style="line-height: 18px;">      }     </li><li style="line-height: 18px;">    }    </li><li style="line-height: 18px;">  }  </li><li style="line-height: 18px;">  return count;  </li><li style="line-height: 18px;">}  </li></ol></div><p> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">上面是关于java中双重检查模式(double-check idiomQ的一般结论。但是事情还没有l束Q因为java的内存模式也在改q中。Doug Lea 在他的文章中写道Q?#8220;Ҏ最新的 JSR133 ?Java 内存模型Q如果将引用cd声明?volatileQ双重检查模式就可以工作?#8221;Q参?nbsp;<a target="_blank" style="color: #336699; text-decoration-line: none;">http://gee.cs.oswego.edu/dl/cpj/updates.html</a> ?/p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">所以以后要?Java 中用双重检查模式,可以使用下面的代码:</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"></p><div bg_java"="" style="width: 700.906px; overflow-y: hidden; position: relative;"><div><div><strong>[java]</strong> <a title="view plain" target="_blank" style="background-image: url("images/default/ico_plain.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">view plain</a><span data-mod="popu_168"> <a title="copy" target="_blank" style="background-image: url("images/default/ico_copy.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">copy</a><div style="position: absolute; left: 563px; top: 1749px; width: 18px; height: 18px; z-index: 99;"></div></span></div></div><ol start="1"><li style="line-height: 18px;">private volatile Resource resource;  </li><li style="line-height: 18px;">public Resource getResource(){  </li><li style="line-height: 18px;">  if (resource == null){   </li><li style="line-height: 18px;">    synchronized(this){   </li><li style="line-height: 18px;">      if (resource==null){  </li><li style="line-height: 18px;">        resource = new Resource();    </li><li style="line-height: 18px;">      }     </li><li style="line-height: 18px;">    }    </li><li style="line-height: 18px;">  }  </li><li style="line-height: 18px;">  return resource;  </li><li style="line-height: 18px;">}  </li></ol></div><p> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">当然了,得是在遵?JSR133 规范?Java 中?/p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">所以,double-check ?J2SE 1.4 或早期版本在多线E或?JVM 调优时由?out-of-order writesQ是不可用的?q个问题?J2SE 5.0 中已l被修复Q可以?volatile 关键字来保证多线E下的单例?/p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"></p><div bg_java"="" style="width: 700.906px; overflow-y: hidden; position: relative;"><div><div><strong>[java]</strong> <a title="view plain" target="_blank" style="background-image: url("images/default/ico_plain.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">view plain</a><span data-mod="popu_168"> <a title="copy" target="_blank" style="background-image: url("images/default/ico_copy.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">copy</a><div style="position: absolute; left: 563px; top: 2148px; width: 18px; height: 18px; z-index: 99;"></div></span></div></div><ol start="1"><li style="line-height: 18px;">public class Singleton {  </li><li style="line-height: 18px;">    private volatile Singleton instance = null;  </li><li style="line-height: 18px;">    public Singleton getInstance() {  </li><li style="line-height: 18px;">        if (instance == null) {  </li><li style="line-height: 18px;">            synchronized(this) {  </li><li style="line-height: 18px;">                if (instance == null) {  </li><li style="line-height: 18px;">                    instance = new Singleton();  </li><li style="line-height: 18px;">                }  </li><li style="line-height: 18px;">            }  </li><li style="line-height: 18px;">        }  </li><li style="line-height: 18px;">        return instance;  </li><li style="line-height: 18px;">    }  </li><li style="line-height: 18px;">}  </li></ol></div><p> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><strong>推荐Ҏ</strong> 是Initialization on Demand HolderQIODHQ,</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">详见 <a target="_blank" style="color: #336699; text-decoration-line: none;">http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom</a></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"> </p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"></p><div bg_java"="" style="width: 700.906px; overflow-y: hidden; position: relative;"><div><div><strong>[java]</strong> <a title="view plain" target="_blank" style="background-image: url("images/default/ico_plain.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">view plain</a><span data-mod="popu_168"> <a title="copy" target="_blank" style="background-image: url("images/default/ico_copy.gif"); background-position: left top; background-repeat: no-repeat; padding: 1px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">copy</a><div style="position: absolute; left: 563px; top: 2597px; width: 18px; height: 18px; z-index: 99;"></div></span></div></div><ol start="1"><li style="line-height: 18px;">public class Singleton {  </li><li style="line-height: 18px;">    static class SingletonHolder {  </li><li style="line-height: 18px;">        static Singleton instance = new Singleton();  </li><li style="line-height: 18px;">    }  </li><li style="line-height: 18px;">      </li><li style="line-height: 18px;">    public static Singleton getInstance(){  </li><li style="line-height: 18px;">        return SingletonHolder.instance;  </li><li style="line-height: 18px;">    }  </li><li style="line-height: 18px;">}  </li></ol></div><p> </p><img src ="http://www.aygfsteel.com/jlin/aggbug/432584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jlin/" target="_blank">fly</a> 2017-06-06 13:36 <a href="http://www.aygfsteel.com/jlin/archive/2017/06/06/432584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式学习W记-观察者模??http://www.aygfsteel.com/jlin/archive/2013/08/11/402673.htmlflyflySun, 11 Aug 2013 15:41:00 GMThttp://www.aygfsteel.com/jlin/archive/2013/08/11/402673.htmlhttp://www.aygfsteel.com/jlin/comments/402673.htmlhttp://www.aygfsteel.com/jlin/archive/2013/08/11/402673.html#Feedback0http://www.aygfsteel.com/jlin/comments/commentRss/402673.htmlhttp://www.aygfsteel.com/jlin/services/trackbacks/402673.html设计模式学习W记-观察者模?/a>

1. 概述

  有时被称作发?订阅模式Q观察者模式定义了一U一对多的依赖关p,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时Q会通知所有观察者对象,使它们能够自动更新自己?/p>

2. 解决的问?/p>

  一个系l分割成一个一些类怺协作的类有一个不好的副作用,那就是需要维护相兛_象间的一致性。我们不希望Zl持一致性而各类紧密耦合Q这样会l维护、扩展和重用都带来不ѝ观察者就是解册cȝ耦合关系的?/p>

3. 模式中的角色

  3.1 抽象主题QSubjectQ:它把所有观察者对象的引用保存C个聚集里Q每个主题都可以有Q何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象?/p>

  3.2 具体主题QConcreteSubjectQ:有关状态存入具体观察者对象;在具体主题内部状态改变时Q给所有登记过的观察者发出通知?/p>

  3.3 抽象观察者(ObserverQ:为所有的具体观察者定义一个接口,在得C题通知时更新自己?/p>

  3.4 具体观察者(ConcreteObserverQ:实现抽象观察者角色所要求的更新接口,以便使本w的状态与主题状态协调?/p>

4. 模式解读

  4.1 观察者模式的cd  

  

  4.2 观察者模式的代码

复制代码
    /// <summary>
    /// 抽象主题c?
    /// </summary>
    public abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();

        /// <summary>
        /// 增加观察?
        /// </summary>
        /// <param name="observer"></param>
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        /// <summary>
        /// U除观察?
        /// </summary>
        /// <param name="observer"></param>
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        /// <summary>
        /// 向观察者(们)发出通知
        /// </summary>
        public void Notify()
        {
            foreach (Observer o in observers)
            {
                o.Update();
            }
        }
    }

    /// <summary>
    /// 抽象观察者类Qؓ所有具体观察者定义一个接口,在得到通知时更新自?
    /// </summary>
    public abstract class Observer
    {
        public abstract void Update();
    }

    /// <summary>
    /// 具体观察者或具体通知者,有关状态存入具体观察者对象;在具体主题的内部状态改变时Q给所有登记过的观察者发出通知。具体主题角色通常用一个具体子cd现?
    /// </summary>
    public class ConcreteSubject : Subject
    {
        private string subjectState;

        /// <summary>
        /// 具体观察者的状?
        /// </summary>
        public string SubjectState
        {
            get { return subjectState; }
            set { subjectState = value; }
        }
    }

    /// <summary>
    /// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本n状态与主题状态相协调
    /// </summary>
    public class ConcreteObserver : Observer
    {
        private string observerState;
        private string name;
        private ConcreteSubject subject;

        /// <summary>
        /// 具体观察者用一个具体主题来实现
        /// </summary>
        public ConcreteSubject Subject
        {
            get { return subject; }
            set { subject = value; }
        }

        public ConcreteObserver(ConcreteSubject subject, string name)
        {
            this.subject = subject;
            this.name = name;
        }

        /// <summary>
        /// 实现抽象观察者中的更新操?
        /// </summary>
        public override void Update()
        {
            observerState = subject.SubjectState;
            Console.WriteLine("The observer's state of {0} is {1}", name, observerState);
        }
    }
复制代码

  4.3 客户端代?/p>

复制代码
    class Program
    {
        static void Main(string[] args)
        {
            // 具体主题角色通常用具体自来来实现
            ConcreteSubject subject = new ConcreteSubject();

            subject.Attach(new ConcreteObserver(subject, "Observer A"));
            subject.Attach(new ConcreteObserver(subject, "Observer B"));
            subject.Attach(new ConcreteObserver(subject, "Observer C"));

            subject.SubjectState = "Ready";
            subject.Notify();

            Console.Read();
        }
    }
复制代码

  q行l果

  

5. 模式ȝ

  5.1 优点

    5.1.1 观察者模式解除了主题和具体观察者的耦合Q让耦合的双斚w依赖于抽象,而不是依赖具体。从而得各自的变化都不会媄响另一边的变化?/p>

  5.2 ~点

    5.2.1 依赖关系q未完全解除Q抽象通知者依旧依赖抽象的观察者?/p>

  5.3 适用场景

    5.3.1 当一个对象的改变需要给变其它对象时Q而且它不知道具体有多个对象有待改变时?/p>

    5.3.2 一个抽象某型有两个斚wQ当其中一个方面依赖于另一个方面,q时用观察者模式可以将q两者封装在独立的对象中使它们各自独立地改变和复用?/p>

 

6. 模式引申Q应用C#中的事g委托来彻底解除通知者和观察者之间的耦合?/p>

   6.1 关于委托的定义:委托是一U引用方法的cd。一旦ؓ委托分配了方法,委托与该方法有相同的行为。委托方法可以像其它MҎ一Ph参数和返回倹{委托可以看作是对函敎ͼҎQ的的抽象,是函数的“c?#8221;Q委托的实例代表一个(或多个)具体的函敎ͼ它可以是多播的?/p>

   6.2 关于事gQ事件基于委托,为委托提供了一U发?订阅机制。事件的订阅与取消与我们刚才讲的观察者模式中的订阅与取消cMQ只是表现Ş式有所不同。在观察者模式中Q订阅用方法AttachQ)来进行;在事件的订阅中?#8220;+=”。类似地Q取消订阅在观察者模式中用DettachQ)Q而事件的取消?#8220;-=”?/p>

 

7. 下面例子分别用观察者模式,事g机制来实?/p>

  7.1 实例描述Q客h付了订单NQ这时胦务需要开具发,出纳需要记账,配送员需要配货?/p>

  7.2 观察者模式的实现

    7.2.1 cd

    

    7.2.2 代码实现

复制代码
    /// <summary>
    /// 抽象观察?
    /// </summary>
    public interface ISubject
    {
        void Notify();
    }

    /// <summary>
    /// 工作岗位Q作里的观察者的抽象
    /// </summary>
    public abstract class JobStation
    {
        public abstract void Update();
    }

    /// <summary>
    /// 具体主题Q这里是客户
    /// </summary>
    public class Customer : ISubject
    {
        private string customerState;

        private IList<JobStation> observers = new List<JobStation>();

        /// <summary>
        /// 增加观察?
        /// </summary>
        /// <param name="observer"></param>
        public void Attach(JobStation observer)
        {
            this.observers.Add(observer);
        }

        /// <summary>
        /// U除观察?
        /// </summary>
        /// <param name="observer"></param>
        public void Detach(JobStation observer)
        {
            this.observers.Remove(observer);
        }

        /// <summary>
        /// 客户状?
        /// </summary>
        public string CustomerState
        {
            get { return customerState; }
            set { customerState = value; }
        }

        public void Notify()
        {
            foreach (JobStation o in observers)
            {
                o.Update();
            }
        }
    }

    /// <summary>
    /// 会计
    /// </summary>
    public class Accountant : JobStation
    {
        private string accountantState;
        private Customer customer;

        public Accountant(Customer customer)
        {
            this.customer = customer;
        }

        /// <summary>
        /// 更新状?
        /// </summary>
        public override void Update()
        {
            if (customer.CustomerState == "已付?/span>")
            {
                Console.WriteLine("我是会计Q我来开具发?/span>");
                accountantState = "已开发票";
            }
        }
    }

    /// <summary>
    /// 出纳
    /// </summary>
    public class Cashier : JobStation
    {
        private string cashierState;
        private Customer customer;

        public Cashier(Customer customer)
        {
            this.customer = customer;
        }

        public override void Update()
        {
            if (customer.CustomerState == "已付?/span>")
            {
                Console.WriteLine("我是出纳员,我给登记入̎?/span>");
                cashierState = "已入?/span>";
            }
        }
    }

    /// <summary>
    /// 配送员
    /// </summary>
    public class Dilliveryman : JobStation
    {
        private string dillivierymanState;
        private Customer customer;

        public Dilliveryman(Customer customer)
        {
            this.customer = customer;
        }

        public override void Update()
        {
            if (customer.CustomerState == "已付?/span>")
            {
                Console.WriteLine("我是配送员Q我来发货?/span>");
                dillivierymanState = "已发?/span>";
            }
        }
    }
复制代码

    7.2.3 客户端代?/p>

复制代码
    class Program
    {
        static void Main(string[] args)
        {

            Customer subject = new Customer();

            subject.Attach(new Accountant(subject));
            subject.Attach(new Cashier(subject));
            subject.Attach(new Dilliveryman(subject));

            subject.CustomerState = "已付?/span>";
            subject.Notify();

            Console.Read();
        }
    }
复制代码

    q行l果Q?/p>

    我是会计Q我来开具发?/span>
    我是出纳员,我给登记入̎?/span>
    我是配送员Q我来发货?/span>

 

  7.3 事g实现

    7.3.1 cd

    

    通过cd来看Q观察者和主题之间已经不存在Q何依赖关pM?/p>

    7.3.2 代码实现

    

复制代码
    /// <summary>
    /// 抽象主题
    /// </summary>
    public interface ISubject
    {
        void Notify();
    }

    /// <summary>
    /// 声明委托
    /// </summary>
    public delegate void CustomerEventHandler();

    /// <summary>
    /// 具体主题
    /// </summary>
    public class Customer : ISubject
    {
        private string customerState;

        // 声明一个委托事Ӟcd?CustomerEventHandler
        public event CustomerEventHandler Update;

        public void Notify()
        {
            if (Update != null)
            {
                // 使用事g来通知l订阅?/span>
                Update();
            }
        }

        public string CustomerState
        {
            get { return customerState; }
            set { customerState = value; }
        }
    }

    /// <summary>
    /// 财务Q已l不需要实现抽象的观察者类Qƈ且不用引用具体的主题
    /// </summary>
    public class Accountant
    {
        private string accountantState;

        public Accountant()
        { }

        /// <summary>
        /// 开发票
        /// </summary>
        public void GiveInvoice()
        {
            Console.WriteLine("我是会计Q我来开具发?/span>");
            accountantState = "已开发票";
        }
    }

    /// <summary>
    /// 出纳Q已l不需要实现抽象的观察者类Qƈ且不用引用具体的主题
    /// </summary>
    public class Cashier
    {
        private string cashierState;

        public void Recoded()
        {
            Console.WriteLine("我是出纳员,我给登记入̎?/span>");
            cashierState = "已入?/span>";
        }
    }

    /// <summary>
    /// 配送员Q已l不需要实现抽象的观察者类Qƈ且不用引用具体的主题
    /// </summary>
    public class Dilliveryman
    {
        private string dillivierymanState;

        public void Dilliver()
        {
            Console.WriteLine("我是配送员Q我来发货?/span>");
            dillivierymanState = "已发?/span>";
        }
    }
复制代码

    7.3.3 客户端代?/p>

复制代码
    class Program
    {
        static void Main(string[] args)
        {

            Customer subject = new Customer();

            Accountant accountant = new Accountant();
            Cashier cashier = new Cashier();
            Dilliveryman dilliveryman = new Dilliveryman();

            // 注册事g
            subject.Update += accountant.GiveInvoice;
            subject.Update += cashier.Recoded;
            subject.Update += dilliveryman.Dilliver;

            /*
             * 以上写法也可以用下面代码来替?
            subject.Update += new CustomerEventHandler(accountant.GiveInvoice);
            subject.Update += new CustomerEventHandler(cashier.Recoded);
            subject.Update += new CustomerEventHandler(dilliveryman.Dilliver);
             */

            subject.CustomerState = "已付?/span>";
            subject.Notify();

            Console.Read();
        }
    }
复制代码

    q行l果

    我是会计Q我来开具发?/span>
    我是出纳员,我给登记入̎?/span>
    我是配送员Q我来发货?/span>



fly 2013-08-11 23:41 发表评论
]]>
վ֩ģ壺 ƽ| ƽ| Ͷ| ˳| ʳ| | ƽ| ̫| | ݸ| | ˳| | | ˫| ̶| | | ڽ| | ѭ| | | | ݶ| | | | ʯɽ| | | | | ˮ| | | Ҧ| Դ| ˫| ڰ| DZ|