Java设计模式之单例模式

Posted llguanli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java设计模式之单例模式相关的知识,希望对你有一定的参考价值。

场景问题

业内都有一个不朽的传说。就是程序猿是找不到女朋友的。没有女朋友怎么行。

今天咱就带着大家用Java的知识。来”追”一个女朋友。
那在追女友之间阿,咱先定一个女友的标准。

只是。这个标准不能乱定是吧。不能像网上流传的一样。”女的,活的”。做为一个有理想的程序猿。我认为我的女朋友,要有身高吧,然后罩杯也不正确低,低重也不好太胖阿。

那么用 Java 语言来表述,就是这个”女友”得有三个属性。身高。体重,与胸围。所以。咱就建这么个类。叫 GirlFriend.

public class GirlFriend {
    private String cup;
    private int height;
    private int weight;

    public String getcup() {
        return cup;
    }

    public void setcup(String cup) {
        this.cup = cup;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

那如今已经准备了一个女友类。

接下来,是不是就要产生一个女朋友了。

那咱们就在client new一个呗。

public class Client {
    public static void main(String[] args) {
        GirlFriend gf = new GirlFriend();
    }
}

问题
大家试想一下。假设我们在client里,再去”找”一个女友,是不是也是能够的。

public class Client {
    public static void main(String[] args) {
        GirlFriend gf = new GirlFriend();
        GirlFriend gf1 = new GirlFriend();
        System.out.println(gf==gf1);
    }
}

并且。上述的代码。终于的结果也是 false。
那,做为一个有原则的男人,是不是要限制这样的情况发现呢。

单例模式

单例模式定义

解决上面问题的一种方式,就是用单例模式。

那么,何谓单例模式?我们先来看一下定义:

保证一个类仅有一个实例,并提供一个它的全局訪问点。

实现方法

在 Java 中。单例模式实现分为两种。一种称为懒汉式,一种又称为饿汉式。

我们分别来看一下这两种方式是怎么实现的。


1:懒汉式

public class GirlFriend {
    private String cup;
    private int height;
    private int weight;
    //定义一个变更来储存实例
    private static GirlFriend  instance =null;
    private GirlFriend(){

    }
    public static GirlFriend getInstance(){
        //推断实例是否为空
        if(null==instance){
            //假设当前实例还没有创建,那就生成一个,并赋值给储存实例
            instance = new GirlFriend();
        }
        return instance;
    }
    //下面都是演示样例方法

    public String getcup() {
        return cup;
    }

    public void setcup(String cup) {
        this.cup = cup;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

2:饿汉式:

public class GirlFriend {
    private String cup;
    private int height;
    private int weight;
    //定义一个变更来储存创建好的实例
    private static GirlFriend  instance =new GirlFriend();
    private GirlFriend(){

    }
    public static  GirlFriend getInstance(){

        return instance;
    }
    //下面都是演示样例方法

    public String getcup() {
        return cup;
    }

    public void setcup(String cup) {
        this.cup = cup;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

3:client调用
那这个时候,我们再调用。得到的就是一个唯一的女友了。

public class Client {
    public static void main(String[] args) {
        GirlFriend gf = GirlFriend.getInstance();
        GirlFriend gf1 =GirlFriend.getInstance();
        System.out.println(gf==gf1);
    }
}

因为我们在女友类里,把构造方法给私有化了,所以。在客端端调用的时候。得到的就是唯一的一个女友对象了。

(在这里,我们临时不考虑反射。)
4:关于命名
事实上,所谓饿汉与懒汉也是一种比較形象的说法吧。


所谓饿汉。也就是说你比較饥渴,饿,于是就在装载类的时候就已经创建好”女友了”。那懒汉。也就是懒。等你须要女友的时候再去创建。

延迟载入与缓存

延迟载入

懒汉式的单例模式体现了延迟载入的思想。那什么是延迟载入。
简单一点来主,延迟载入就是一開始不去载入数据或者资源,等到要用到的时候,才去载入,也就是 Lazy Load。

这在实际开发中也是一种常见的思想,尽可能的节约资源。

缓存

懒汉式还体现了缓存的思想,缓存在开发中也是常见的功能。
简单的来说,就是当某些资源须要被重复使用的时候,而这些资源储存在系统外部。比方数据库,硬盘等。那假设每次操作都要又一次读取一次。显然非常浪费资源。所以,懒汉式载入中,在一開始,就定义了一个变量。来储存要生成的实例。也就是:

private static GirlFriend  instance =null;

之后,再生成实例后,赋值给变量。

线程安全

从线程安全性上来讲。不加同步的懒汉式是线程不安全的。

也就是说。假设多个线程同一时候调用getInstance方法,就会导制并发问题。那该怎样解决。

事实上仅仅要加上 synchronized就能够了。也就是:

  public static synchronized GirlFriend getInstance(){}

可是这样一来,就会降低訪问速度。并且每次都要推断。那该怎样实现,这里就要用到双重加锁。


所谓双重加锁。指的是。不是每一次 getInstance都要同步。

而是先不同步,进入方法之后,先检查实例是否存在。

假设不存在。再进入同步块,这是第一重检查。进入同步块之后。再次检查实例是否存在,假设不存在。就在同步情况下创建一个实例。这是第二重检查。这样一来,就能够降低多次在同步情况下进行推断所浪费的时间了。
实现代码例如以下:

  private volatile static GirlFriend  instance =null;
    public static  GirlFriend getInstance(){
        if(null==instance){
            synchronized (GirlFriend.class){
                if(instance==null){
                    instance = new GirlFriend();
                }
            }
        }
        return instance;
    }

注:双重载入须要在 java5以上的版本号。

枚举

事实上,另一种更高效的单例实现。也就是单元素的枚举。关于枚举的介绍,我这里就不多做介绍了。

我们看一下怎样用枚举实现单例。

public enum  GirlFriend {
    instance;
    private String cup;
    private int height;
    private int weight;
    //下面都是演示样例方法

    public String getcup() {
        return cup;
    }

    public void setcup(String cup) {
        this.cup = cup;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

使用枚举实现单例会使代码更加的简洁。并且。从 JVM 上绝对的防止了多次实例化。













以上是关于Java设计模式之单例模式的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式——创建型模式之单例模式

Java模式设计之单例模式(二)

Java设计模式之单例模式

设计模式之单例模式(Java实现)

Java之单例模式(Singleton)

设计模式之单例模式