【Java设计模式】浅谈设计模式(二)之单例模式
2017-03-24 15:38
507 查看
一、单例模式概述
单例模式,笔者的理解就是单实例模式。怎么来说呢?打个比方,我们都知道一山不容二虎,一个山头出现了两只老虎那么必然会出现一些争斗,一些伤亡。那么在程序中会出现什么样的“虎”呢?比如:配置文件、工具类、线程池、缓存、日志对象等。如果创建了多个,那么就可能出现占用过多资源,数据读取不一致等等不是期望中的结果。
那么保证程序中上述性质实例有且只有一个呢?这就要依靠单例模式了。
二、单例模式的饿汉式实现
创建一个类Singleton.java,假设这个类的对象实例在程序中有且只能有一个。另外创建Test.java来模拟外部对Singleton类的访问。至此,我们有以下认识:
在Test.java的main()方法中必然可以通过调用Singleton类的默认构造方法来生成多个不同的实例
那么我们如何防止这种情况发生呢?一个有效的思路就是:
第一步:将Singleton类的构造方法声明为private,则在main()方法中就不能直接调用其构造方法了,也就不能产生任何实例了。
第二步:由于我们需要仅一个实例,所以可以在Singleton类里面实例化一个实例成员。虽然在类里面有一个实例成员,但是访问类成员得先实例化对象才能访问,这仿佛就像产生了死循环一般了。
第三步:通过把这个实例声明为static就可以通过类名来访问了。
示例代码如下:
1)Singleton.java:
2)Test.java:
3)运行结果:
但是这样做的话就违背了面向对象编程中的安全原则,为此我们需要将实例做访问控制即声明为private,这样就不能直接通过类名来访问了。从而需要添加一个静态方法来获取这个静态实例。如下:
Singleton.java:
当然相应的,外部访问代码也应做修改:通过调用这个公有的静态方法来获取唯一的实例。运行程序,仍然可以知道s1和s2为同一实例。
三、单例模式的懒汉式实现
我们还是三步走:
将构造方法私有化,不允许外部直接创建对象。
声明类的唯一实例,以private static 修饰。
提供一个用户获取实例的方法,用public static 修饰。
注:和饿汉模式的区别就在于实例化对象的位置,具体参见代码。
Singleton.java:
Test.java做相应修改,运行可以发现仍然为同一个实例。
四、饿汉模式和懒汉模式的区别
根据上述饿汉式和懒汉式在实现上的细微差别,可以得出如下结论:
由于饿汉式实现在声明唯一对象的时候已经初始化,故而当类加载的时候将同时实例化这个唯一的对象。具有类加载慢,获取对象快的特点。
而懒汉模式在类加载的时候不会同时实例化这个唯一的对象,它只有当外部第一次时才实例化。具有类加载快,运行时获取对象的速度比较慢的特点。
第三个区别可能隐藏得比较深:饿汉模式是线程安全的,而懒汉模式不是线程安全的。
单例模式,笔者的理解就是单实例模式。怎么来说呢?打个比方,我们都知道一山不容二虎,一个山头出现了两只老虎那么必然会出现一些争斗,一些伤亡。那么在程序中会出现什么样的“虎”呢?比如:配置文件、工具类、线程池、缓存、日志对象等。如果创建了多个,那么就可能出现占用过多资源,数据读取不一致等等不是期望中的结果。
那么保证程序中上述性质实例有且只有一个呢?这就要依靠单例模式了。
二、单例模式的饿汉式实现
创建一个类Singleton.java,假设这个类的对象实例在程序中有且只能有一个。另外创建Test.java来模拟外部对Singleton类的访问。至此,我们有以下认识:
在Test.java的main()方法中必然可以通过调用Singleton类的默认构造方法来生成多个不同的实例
那么我们如何防止这种情况发生呢?一个有效的思路就是:
第一步:将Singleton类的构造方法声明为private,则在main()方法中就不能直接调用其构造方法了,也就不能产生任何实例了。
第二步:由于我们需要仅一个实例,所以可以在Singleton类里面实例化一个实例成员。虽然在类里面有一个实例成员,但是访问类成员得先实例化对象才能访问,这仿佛就像产生了死循环一般了。
第三步:通过把这个实例声明为static就可以通过类名来访问了。
示例代码如下:
1)Singleton.java:
package com.bebdong.Singleton_pattern; public class Singleton { private Singleton(){ } static Singleton instance=new Singleton(); }
2)Test.java:
package com.bebdong.Singleton_pattern; public class Test { public static void main(String[] args) { Singleton s1=Singleton.instance; Singleton s2=Singleton.instance; if(s1==s1) System.out.println("s1和s2是同一实例"); if(s1!=s2) System.out.println("s1和s2不是同一实例"); } }
3)运行结果:
但是这样做的话就违背了面向对象编程中的安全原则,为此我们需要将实例做访问控制即声明为private,这样就不能直接通过类名来访问了。从而需要添加一个静态方法来获取这个静态实例。如下:
Singleton.java:
package com.bebdong.Singleton_pattern; public class Singleton { private Singleton(){ } private static Singleton instance=new Singleton(); public static Singleton getInstance(){ return instance; } }
当然相应的,外部访问代码也应做修改:通过调用这个公有的静态方法来获取唯一的实例。运行程序,仍然可以知道s1和s2为同一实例。
三、单例模式的懒汉式实现
我们还是三步走:
将构造方法私有化,不允许外部直接创建对象。
声明类的唯一实例,以private static 修饰。
提供一个用户获取实例的方法,用public static 修饰。
注:和饿汉模式的区别就在于实例化对象的位置,具体参见代码。
Singleton.java:
package com.bebdong.Singleton_pattern; public class Singleton { private Singleton(){ } private static Singleton instance; //只声明,不实例化 public static Singleton getInstance(){ if(instance==null){ //用一个判断条件确定需不需要实例化 instance=new Singleton(); } return instance; } }
Test.java做相应修改,运行可以发现仍然为同一个实例。
四、饿汉模式和懒汉模式的区别
根据上述饿汉式和懒汉式在实现上的细微差别,可以得出如下结论:
由于饿汉式实现在声明唯一对象的时候已经初始化,故而当类加载的时候将同时实例化这个唯一的对象。具有类加载慢,获取对象快的特点。
而懒汉模式在类加载的时候不会同时实例化这个唯一的对象,它只有当外部第一次时才实例化。具有类加载快,运行时获取对象的速度比较慢的特点。
第三个区别可能隐藏得比较深:饿汉模式是线程安全的,而懒汉模式不是线程安全的。
相关文章推荐
- Java设计模式浅谈
- java设计模式---浅谈2种工厂模式和单例模式
- 浅谈 java 设计模式--命令行模式(Command pattern)
- 浅谈23种java设计模式
- 浅谈java中的单态设计模式
- Java设计模式浅谈
- 浅谈 java 设计模式--装饰模式(Decorator pattern)
- 浅谈java中的单态设计模式
- 浅谈 java 设计模式--简单工厂模式(Simple Factory pattern)
- 黑马程序员_浅谈JAVA设计模式
- java设计模式---浅谈2种工厂模式和单例模式
- 浅谈 java 设计模式--抽象工厂模式(AbstractFactory pattern)
- 浅谈 java 设计模式--策略模式(Strategy pattern)
- 浅谈Java设计模式之---策略模式
- 浅谈BREW对面向对象,Windows,Java,设计模式的借鉴
- java设计模式---浅谈2种工厂模式和单例模式
- 浅谈 java 设计模式--构建模式(Builder pattern)
- 浅谈 java 设计模式--单例模式(Singleton pattern)
- JAVA的设计模式浅谈
- 浅谈Java设计模式之------代理模式