单例模式_张雷杰_第1页
单例模式_张雷杰_第2页
单例模式_张雷杰_第3页
单例模式_张雷杰_第4页
单例模式_张雷杰_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、PPT模板下载: 主讲:张雷杰目的单例模式确保一个类仅有一个实例,且提供它的一个全局访问点原因有时我们只想让一个类的单个实例在系统中存在。我们需要让该实例易于被访问并且我们想要确保该类的其他实例不能被创建单例模式单例模式结构单例模式优点对惟一实例的受控访问允许可变的实例数量能避免实例重复创建应用于避免存在多个实例引起程序逻辑错误的场合较节约内存单例模式的实现我们将使用静态方法来允许客户获得对单个实例的引用,并且将使用私有构造器!/* * Singleton类是只允许一个实例化的类的实现 */public class Singleton / The private reference to th

2、e one and only instance.private static Singleton uniqueInstance = null;/ An instance attribute.private int data = 0;单例模式的实现/* * Returns a reference to the single instance. * Creates the instance if it does not yet exist. * (This is called lazy instantiation.) */public static Singleton instance() if(

3、uniqueInstance = null) uniqueInstance = new Singleton();return uniqueInstance; 单例模式的实现/* * The Singleton Constructor. * Note that it is private! * No client can instantiate a Singleton object! */private Singleton() / Accessors and mutators here!单例模式的实现以下是测试程序public class TestSingleton public static

4、void main(String args) / Get a reference to the single instance of Singleton.Singleton s = Singleton.instance();/ Set the data value.s.setData(34);System.out.println(First reference: + s);System.out.println(Singleton data value is: +s.getData();单例模式的实现/ Get another reference to the Singleton./ Is it

5、 the same object?s = null;s = Singleton.instance();System.out.println(nSecond reference: + s);System.out.println(Singleton data value is: +s.getData();outputsFirst reference: Singleton1cc810Singleton data value is: 34First reference: Singleton1cc810Singleton data value is: 34单例模式的实现注意:单例只在需要时才创建。这被称

6、作被动实例化。如果两个线程同时调用instance() 方法会怎么样?会产生什么问题?思考实验如何能预防这种情况哪?有几个方法:单例模式的实现单例模式的实现下面是具有主动实例化的单例模式。我们将在静态初始化器中创建Singleton实例。保证这种做法是线程安全的。/* * Singleton 类是只允许一个实例化的类的实现。 */public class Singleton / The private reference to the one and only instance. / Lets eagerly instantiate it here. private static Single

7、ton uniqueInstance = new Singleton(); / An instance attribute. private int data = 0;单例模式的实现 /* * Returns a reference to the single instance. */ public static Singleton instance() return uniqueInstance; /* * The Singleton Constructor. * Note that it is private! * No client can instantiate a Singleton

8、 object! */ private Singleton() / Accessors and mutators here!主动实例化与被动实例化的区别主动实例化:在主动实例化:在uniqueInstance被加被加载时就将自己实例化。为静态实例化方载时就将自己实例化。为静态实例化方式。它在静态初始化期间或在类的构造式。它在静态初始化期间或在类的构造器中分配变量。类一加载就实例化,所器中分配变量。类一加载就实例化,所以要提前占用系统资源。以要提前占用系统资源。被动实例化在第一次被引用时,才会将被动实例化在第一次被引用时,才会将自己实例化。面临多线程访问的安全性自己实例化。面临多线程访问的安全性

9、问题,需要作双重锁定来保证安全。问题,需要作双重锁定来保证安全。具有子类的Singleton如果想要能够生成Singleton的子类并让单个实例是子类的实例时该怎么办?例如,假定MazeFactory已生成子类 EnchantedMazeFactory 和 AgentMazeFactory。我们只想实例化一个工厂,或者EnchantedMazeFactory 或者是AgentMazeFactory。我们能怎样做哪?有几个方法:=由MazeFactory 的静态instance() 方法决定某个子类的实例来实例化。这项工作能通过参数或环境变量来完成。在这种情况下子类的构造器不能是私有的,因此客户

10、端不能实例化子类的其他实例。=由每个子类提供一个静态的instance() 方法。现在子类的构造器可以是私有的。具有子类的Singleton方法1方法1:由MazeFactory 的instance() 方法决定将实例化的子类/* * MazeFactory 类是只允许一个子类实例化的类的实现 */public abstract class MazeFactory / The private reference to the one and only instance. private static MazeFactory uniqueInstance = null; / The MazeFa

11、ctory constructor. / If you have a default constructor, it can not be private / here! protected MazeFactory() 具有子类的Singleton方法1 / Return a reference to the single instance. / If instance not yet created, create enchanted as default. public static MazeFactory instance() if (uniqueInstance = null) ret

12、urn instance(enchanted); else return uniqueInstance; / Create the instance using the specified String name. 具有子类的Singleton方法1public static MazeFactory instance(String name) if (uniqueInstance = null) if (name.equals(enchanted)uniqueInstance = new EnchantedMazeFactory(); else if (name.equals(agent)un

13、iqueInstance = new AgentMazeFactory(); return uniqueInstance; 具有子类的Singleton方法1首先是创建工厂的客户代码:然后是访问工厂的客户代码:注意:EnchantedMazeFactory和AgentMazeFactory 的构造器不能是私有的,因为MazeFactory必须能够实例化它们。因此,客户不可能实例化这些子类的其他实例。MazeFactory factory = MazeFactory.instance(enchanted);MazeFactory factory = MazeFactory.instance();

14、具有子类的Singleton方法1(续)The instance(String) 方法违反了开-闭原则,因为每个MazeFactory的新子类都必须修改它。public static MazeFactory instance(String name) if (uniqueInstance = null)uniqueInstance = Class.forName(name).newInstance();return uniqueInstance;我们可以将Java类名作为instance(String)方法的参数来使用,以产生更简单的代码:具有子类的Singleton方法2方法2: 由每个子类

15、提供一个静态的instance() 方法/* * MazeFactory类是只允许一个子类实例化的类的实现 * 该版本要求其子类提供静态instance() 方法的实现 */public abstract class MazeFactory / The protected reference to the one and only instance. protected static MazeFactory uniqueInstance = null; 具有子类的Singleton方法2 / The MazeFactory constructor. / If you have a defaul

16、t constructor, it can not be private / here! protected MazeFactory() / Return a reference to the single instance. public static MazeFactory instance() return uniqueInstance;具有子类的Singleton方法2 /* * Class EnchantedMazeFactory is an implementation of a class * that only allows one instantiation. */publi

17、c class EnchantedMazeFactory extends MazeFactory / Return a reference to the single instance. public static MazeFactory instance() if(uniqueInstance = null)uniqueInstance = new EnchantedMazeFactory(); return uniqueInstance; / Private subclass constructor! private EnchantedMazeFactory() 具有子类的Singleto

18、n方法2首先是创建工厂的客户代码:然后是访问工厂的客户代码:注意:子类的构造器现在是私有的。只能创建子类的一个实例!MazeFactory factory = EnchantedMazeFactory.instance();MazeFactory factory = MazeFactory.instance();也要注意到如果在惟一的实例被创建前客户就调用MazeFactory.instance() ,客户就能到一个null引用。最后,注意uniqueInstance 现在是被保护的!单例模式是应用最广的模式之一,确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,应用在一些创建

19、对象需要消耗较多资源的地方。定义单例模式实现方式1.懒汉模式,2.Double CheckLock(DCL)实现单例,3.静态内部类,4.枚举单利,5.使用容器实现单例模式懒汉模式懒汉模式是申明一个静态变量,在用户首次调用getInstance时进行初始化public class Singleton private static Singleton instance; private Singleton() public static synchronized Singleton getInstance() if(instance = null) instance = new Singleto

20、n(); return instance; 饿汉模式的话就在类加载的时候直接初始化 private static Singleton instance = new Singleton(); 每一次调用都需要进行同步,造成不必要的开销(一般不建议使用)DCL实现单例优点是能够在需要时才初始化,又能保证线程安全且单例对象初始化后调用getInstance不进行同步锁public class Singleton private static Singleton instance = null; private Singleton() public static Singleton getInstan

21、ce() if(instance = null) /主要为了避免不必要的同步 synchronized(Singleton.class) if(instance = null) /为了在空的情况下创建实例 instance = new Singleton(); return instance; DCL实现单例instance = new Singleton();的实际操作:1.给Singleton分配内存,2调用Singleton的构造函数,初始化成员字段,3将instance对象指向分配的内存空间但是Java编译器允许处理器乱序执行,已经JDK1.5之前JMM(Java Memory Mod

22、el)中Cache,寄存器到主内存回写顺序的规定执行顺序可能是123,也可能是132,如果是132就会出现instance不是空,但是使用的时候会有问题,1.6开始已经作了调整,利用Private volatile static Singleton instance = null;就可以保证安全性,但是会消耗一些性能优点:资源资源利用率高,是使用最多的单利实现方式,可以满足绝大多数的单例,但是在一些高并发或者JDK1.6版本以下使用会有创建失败的可能性静态内部类DCL存在一定的失效问题,所以不赞成使用,建议使用如下代码代替:public class Singleton private Sing

23、leton() public static Singleton getInstance() return SingletonHolder.sInstance; /*静态内部类*/ private static SingletonHolder private static final Singleton sInstance = new Singleton();第一次加载Singleton时不会初始化sInstance,只有第一次调用getInstance的时候才会初始化,因此导致虚拟机加载SingletonHolder类,这种方式不仅能保证线程安全,也能保证唯一性和延迟加载,推荐使用枚举单例默认

24、枚举类实例是线程安全的,并且在任何情况下它都是一个单例public enum SingletonEnum() INSTANCE; public void doSomething() System.out.println(=); 反序列化:在上述的集中单例模式中,反序列化会导致对象的重新创建(即使构造方法是私有的也会),但是反序列化操作提供了一个很特别的函数readResolve(),这个方法可以控制对象的反序列化;private Object readResolve() throws ObjectStreamException return sInstance;使用容器实现单例模式在程序初始化

25、的时候将多种单例类注入到统一的管理类中,再用key进行获取public class SingletonManager private static Map objMap = new HashMap(); private Singleton() public static void registerService(String key, Object instance) if (!objMap.containsKey(key) objMap.put(key,instance); public static Object getService(String) return objMap.get(k

26、ey); Java实例-系统日志(续)几乎所有的系统都需要日志记录,其设计的原理就是采用单例模式,用文件提供日志记录,所有关联的日志都记录在同一个文件中。其实现的代码如下Public class Client public static void main(String args) /初始化 Logger Logger.initialize(); /获得实例 Logger loger=Logger.getLogger(); loger.logMsg(“client log message”); 先看客户调用程序:Logger.initialize();Java实例-系统日志(续)import

27、java.text.SimpleDateFormat;import java.util.GregorianCalendar;import java.util.Properties;import java.io.InputStream;import java.io.FileOutputStream;import java.io.PrintStream;import java.io.IOException;public class Logger private String fileName; private Properties properties; private Priority prio

28、rity; Logger的详细调用:Java实例-系统日志(续)/* * Private constructor构造函数是私有的,因此,此类不能被继承 */ private Logger () logger = this; /* * 日志级别:错误或信息等 * * return level, int */ public int getRegisteredLevel () int i = 0; private Logger () logger = this; Java实例-系统日志(续)try InputStream inputstream = getClass ().getResourceAs

29、Stream ( Lperties); properties.load (inputstream); inputstream.close (); i = Integer.parseInt (properties.getProperty ( *logger.registeredlevel*); if (i 3) i = 0; catch (Exception exception) System.out.println (Logger: Failed in the getRegisteredLevel method);Java实例-系统日志(续) exception.printS

30、tackTrace (); return i;/* * One file will be made daily. So, putting date time in file * name. * * param gc GregorianCalendar * return String, name of file */private String getFileName (GregorianCalendar gc) SimpleDateFormat dateFormat1 = new SimpleDateFormat (dd-MMM-yyyy);Java实例-系统日志(续) String dateString = dateFormat1.format (g

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论