




已阅读5页,还剩30页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
创建型单件模式(singleton) 独一无二的对象 用来创建独一无二的,只能有一个实例的对象 的入场券 单件模式的类图可以说是所有模式的类图中最 简单的,其实上,它的类图上只有一个类 尽管从类设计的视角来说立很简单,但是实现 上还是会遇到相当多的波折 有一些对象其实我们只需要一个,例如:线程池 (threadpool)、缓存(cache)、对话框、处理偏好设置和 注册表(registry)的对象、日志对象,充当打印机、显 卡等设备的驱动程序的对象 事实上,这些类对象只能有一个实例,如果制造出多 个实例,就会导致许多问题产生,例如:程序的行为 异常、资源使用过量,或者是不一致的结果 或许的确有一些类应该只存在一个实例,但这需要花 整个章节的篇幅来说明吗?难道不能靠程序员之间的 约定或是利用全局变量做到?利用java的静态变量就 可以做到 单件模式是经得起时间考验的方法,可以确保只有一 个实例会被创建,单件模式也给了我们一个全局的访 问点,和全局变量一样方便,又没有全局变量的缺点 举例来说:如果将对象赋值给一个全局变量,那么你 很可能在程序一开始就创建好对象。万一这个对象非 常耗费资源,而程序在这次的执行过程中又一直没用 到它,不就形成浪费了吗?稍后你会看到利用单件模式 ,我们可以在需要时才创建对象 利用静态类变量、静态方法和适当的访问修饰符 (access modifier),你的确可以做到这一点。但是不管 使用哪一种方法,能够了解单件的运作方式仍然是很 有趣的事 单件模式听起来简单,要做得对可不简单 要如何保证一个对象只能被实例化一次?答案可不是 三言两语就说得完的 小小单件苏格拉底式的诱导 问答 如何创建一个对象?new myobject(); 万一另一个对象想创建myobject会怎 样?可以再次new myobject吗? 是的,当然可以 所以,一旦有一个类,我们是否都能 多次地实例化它? 如果是公开的类,就可以 如果不是的话,会怎样?如果不是公开类,只有同一个包内的类可 以实例化它,但是仍可以实例化它多次 嗯,有意思!你知道可以这么做吗?我没想过。但是,这是合法的定义,有一 定的道理 怎么说呢?我认为含有私有的构造器的类 不能被实例化 小小单件苏格拉底式的诱导问答(续 ) 有可以使用私有的构造器的对象吗? 嗯,我想myclass内的代码是唯一能 调用此构造器的机构。但是这又不太 合乎常理 为什么?因为必须有myclass类的实例才能调用 myclass构造器,但是因为没有其他类能 够实例化myclass,所以我们得不到这样 的实例。这是“鸡生蛋,蛋生鸡”的问题。 我可以在myclass类型的对象上使用 myclass构造器,但是在这之前,必须有 一个myclass实例。在产生mycalss实例 之前,又必须在myclass实例内才能调用 私有的构造器 嘿!我有个想法。你认为这样如何? myclass有一个静态方法。我们可以这样 调用这个方法: 小小单件苏格拉底式的诱导问答(续 ) 为何调用的时候用myclass的类名, 而不是用对象名? 因为getinstance()是一个静态方法, 换句话说,是一个“类”方法。引用一 个静态方法,你需要使用类名。 有意思。假如把这些合在一起“是 否”就可以初始化一个myclass? 当然可以。 好了,你能想出第二种实例化对象的 方式吗? 嗯,大概可以吧你能够完成代码使myclass只有一 个实例被产生吗? 剖析经典的单件模式实现 延迟实例化(lazy instantiaze) 巧克力工厂 现代化的巧克力工厂具备计算机控制的巧 克力锅炉。锅炉做的事就是把巧克力和牛 奶融在一起,然后送到下一个阶段,以制 造成巧克力棒 这里有4个choc-o-holic公司的工业强度 巧克力锅炉控制器 看看它的代码(chocolateboiler),你会 发现代码写得相当小心,他们在努力防止 不好的事情发生 例如:排出500加仑的未煮沸的混合物, 或者锅炉已经满了还继续放原料,或者锅 炉内还没放原料就开始空烧 choc-o-holjc 公司在有意识地防止不好的事情发生 你可能会担心,如果同时存在两个chocolateboiler ( 巧克力锅炉)实例,可能将发生很糟糕的事情 万一同时有多于一个的chocolateboiler (巧克力锅炉 )实例存在,可能发生哪些很糟糕的事呢? 定义单件模式 单件模式确保一个类只有一个实例,并提供一 个全局访问点 我们正在把某个类设计成自己管理的一个唯 独实例,同时也避免其他类再自行产生实例 。要想取得单件实例,通过单件类是唯一的 途径 我们也提供对这个实例的全局访问点:当你 需要实例时,向类查询,它会返回单个实例 。前面的例子利用延迟实例化的方式创建单 件,这种做法对资源敏感的对象特别重要 类图 我们遇到麻烦了 看起来巧克力锅炉要让我们失望了,尽管我们利用 经典的单件来改进代码,但是chocolateboiler的 fill()方法竟然允许在加热的过程中继续加入原料 这可是会溢出五百加仑的原料(牛奶和巧克力)呀!怎 么会这样!? 线程是个问题 多加线程,就会造成这样吗? 不是只要为chocolatebolier的单件设置好 uniquelnstance变量,所有的getlnstance()调 用都会取得相同的实例吗?对不对? 化身为jvm 这里有两个线程都要执行这段代码 你的工作是扮演jvm角色并判断出两个线程是 否可能抓住不同的锅炉对象而扰乱这段代码 提示:你只需要检查getinstance()方法内的操作次序 和uniqueinstance的值,看它们是否互相重叠 用代码帖来帮你研究这段代码为什么可能产生两个 锅炉对象 处理多线程 只要将getinstance()变成同步(synchronized) 方法,多线程灾难几乎就可以轻易地解决了 说得很对,的确是有一点不好 而比你所想象的还要严重一些的 是:只有第一次执行此方法时, 才真正需要同步 换句话说,一旦设置好 uniquelnstance变量,就不再需 要同步这个方法了 之后每次调用这个方法,同步都 是一种累赘 能够改善多线程吗? 为了要符合大多数java应用程序,很明显地,我 们需要确保单件模式能在多线段的状况下正常工 作 但是似乎同步getinstance()的做法将拖垮性能, 该怎么办呢? 可以有一些选择 如果getinstance()的性能对应用程序不是很关键 ,就什么都别做 如果你的应用程序可以接受getlnstance()造成的额外 负担,就忘了这件事吧 同步getlnstance()的方法既简单又有效 但是你必须知道,同步一个方法可能造成程序执行效 率下降100 倍 因此,如果将getlnstance()的程序使用在频繁运行的 地方,你可能就得重新考虑了 使用“急切”创建实例,而不用延迟实例化的做法 如果应用程序总是创建并使用单件实例,或者在创建和运行时的 负担不太繁重,你可能想要急切(eagerly) 创建此单件,如下所示: 利用这个做法,我们依赖jvm在加载这个类时马上创建 此唯一的单件实例 jvm保证在任何线程访问 uniqueinstance静态变 量之前 ,一定先创建此实例 双重检查加锁 用“双重检查加锁”,在getlnstance()中减少使用同步 利用双重检查加锁(double-checked locking),首先检查是否实 例已经创建了,如果尚未创建,“才”进行同步 这样一来,只有第一次会同步,这正是我们想要的 如果性能是你关心的重点,那么这个做法可 以帮你大大地减少getlnstance()的时间 耗费 再度回到巧克力工厂 在研究如何摆脱多线程的梦魇同时,巧克力锅炉也被 清理干净可以再度开工了 首先,得处理多线程的问题 我们有一些选作方案,每个方案部有优缺点,到底该 采用哪一个? 一个实用的例子:属性管理器 什么是属性文件 配置信息在属性文件中以属性的方式存放,一个属性就 是两个字符串组成的键值对,一个字符串是键(key),另 一个是这个键的对应的值(value) 大多数的系统都有一些配置常量,如果把这些常量存储 在程序内部的,那么每一次修改它们都需要重新编译程 序 将这些常量放在配置文件中,系统通过访问这个配置文 件取得配置常量,就可以通过修改配置文件而无需修改 程序而达到更改系统配置的目的 系统也可以在配置文件中存储一些工作环境信息,这样 在系统重启时,这些信息可以延续到下一个运行周期中 示例sperties java 属性类 java 提供了一个工具类,称做属性类,可以用来完成 java 属性和属性文件的操作 属性类的继承关系图 属性类提供了读取属性和设置属性的各种方法 其中其中读取属性读取属性的方法有:的方法有: contains(object contains(object value)value)、containskey(objectcontainskey(object key) key) getproperty(stringgetproperty(string key)key)、getproperty(stringgetproperty(string key, string key, string default)default) list(printstreamlist(printstream s)s)、list(printwriterlist(printwriter w) w) size()size() 设置属性的方法有:设置属性的方法有: put(object key, object value)put(object key, object value) remove(object key)remove(object key) 从属性文件加载属性的方法从属性文件加载属性的方法: : load(inputstreamload(inputstream instreaminstream) ) 将属性存入属性文件的方法将属性存入属性文件的方法: : store(outputstreamstore(outputstream out, string out, string header)header) 为什么需要使用单例模式 属性是系统的一种“资源”,应当避免有多 余一个的对象读取特别是存储属性 属性的读取可能会在很多地方发生,创建属 性对象的地方应当在哪里不是很清楚 属性管理器应当自己创建自己的实例,并且 自己向系统全程提供这一事例 系统设计 系统的核心是一个属性管理器,也就是一 个叫做configmanager的类,这个类是一 个单件类 这个类应当有一个静态工厂方法,不妨叫 做getinstance(),用于提供自己的实例 为简单起见,在这里采取“饿汉”方式实 现configmanager configman
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年销售代表高级面试必-备问题与答案解析
- 【教案版】小学一班级上册 走与跑
- 2025年机电维修工程师应聘面试题解析与技巧
- 2025年特岗教师招聘笔试初中化学冲刺题
- 2025年大学英语四六级考试听力突破技巧
- 2025年山西省朔州市应县中考化学二模试卷
- 电信行业知识培训课件
- 2025年烟草专卖法律法规在遴选考试中的实际应用案例
- 2025年初级焊工技能考试试题及答案详解
- 2025年救援技巧速成救护员考试全真模拟及答案解读
- 医院护理管理课件
- 软件咨询面试题目及答案
- 2025年艾梅乙知识竞赛试题及答案
- 云南航空产业投资集团招聘笔试真题2024
- 2025年农产品质量安全追溯体系构建与农业供应链管理创新报告
- 临时救助政策解读
- 煤矿笔试题目及答案
- 2025年危化品经营单位安全管理人员培训全国考试题库(含答案)
- 广西统考卷(走到田野去)-2025年中考语文作文题解读
- 2025至2030年中国室内覆盖施工行业市场发展监测及投资战略咨询报告
- 2025年高考语文全国一卷试题真题及答案详解(精校打印)
评论
0/150
提交评论