设计模式-单例模式、多例模式

单例设计模式

正常情况下一个类可以创建多个对象

public static void main(String[] args) {
	// 正常情况下一个类可以创建多个对象
	Person p1 = new Person();
	Person p2 = new Person();
	Person p3 = new Person();
}

但是有些时候的某些类, 我们希望只能创建单一的一个对象, 这时候我们需要使用到单例设计模式, 下面我们来介绍一下单例设计模式.

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例设计模式的作用

  • 目的: 保证一个类仅有一个实例,并提供一个访问它的全局访问点
  • 解决的问题: 一个全局使用的类频繁地创建与销毁。
  • 什么时候使用: 当您想控制实例数目,节省系统资源的时候。

单例设计模式的实现步骤

  1. 构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量
  3. 定义一个静态方法返回这个唯一对象

饿汉式

饿汉单例设计模式就是使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故被称为“饿汉模式”。

代码如下:

public class Singleton {
    // 1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
    private Singleton() {}

    // 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
    private static final Singleton instance = new Singleton();
    
    // 3.定义一个静态方法返回这个唯一对象。
    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式

懒汉单例设计模式就是调用getInstance()方法时实例才被创建,先不急着实例化出对象,等要用的时候才例化出对象。不着急,故称为“懒汉模式”。

懒汉式-普通方式【不能用】

(1) 实现步骤
  1. 私有构造方法
  2. 创建一个对象的声明, 但是不实例化.
  3. 对外暴露一个用于获取对象的静态方法
    • 判断对象是否为空
    • 如果为空就实例化
    • 返回当前对象
(2) 代码实现
package com.itheima._01single.demo02;
/**
 *
 * 懒汉式
 *  懒: 上来不着急创建对象, 什么时候用, 什么时候创建
 *
 */
public class Singleton {
    // 1. 私有构造
    private Singleton() {}
    // 2. 只声明本类的引用, 后面不创建对象
    private static Singleton instance;
    // 3. 提供公共的用来获取本类对象的方法
    public static Singleton getInstance() {
        // 判断: 如果instance为null  => 创建对象
        if (instance == null) {
            // 为了看到效果, 所以让线程睡一会
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 什么时候用, 什么时候创建
            instance = new Singleton();
        }
        // 如果instance不为null, 直接返回
        return instance;
    }
}
(3) 优缺点
  • 优点: 起到了懒加载的效果
  • 缺点: 多线程环境下会出现问题, 可能创建出多个实例, 不符合单例的原则.

结论: 在实际开发中不要使用这种方式.

懒汉式 - 同步方法【能用】

(1) 实现步骤
  1. 私有构造方法

  2. 类的内部创建对象

  3. 对外暴露一个用于获取对象的静态同步方法

    • 判断对象是否为空

    • 如果为空就实例化

    • 返回当前对象

(2) 代码实现
package com.itheima._01single.demo03;

/**
 * 懒汉式 - 同步方法
 */
public class Singleton {
    // 1. 私有构造
    private Singleton() {
    }

    // 2. 声明引用
    private static Singleton instance; // 实例

    // 3. 获取对象的方法
    public static synchronized Singleton getInstance() {
        // 判断, 如果为null, 创建对象
        if (instance == null) {

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            instance = new Singleton();
        }
        // 如果不为null, 直接返回
        return instance;
    }


}

(3) 优缺点

优点: 解决了多线程中创建多个对象的问题

缺点: 效率太低, 每次执行都要进入同步方法.

总结: 实际开发中不推荐使用

懒汉式 - 同步代码块【过渡】

(1) 实现步骤
  1. 私有构造方法

  2. 类的内部创建对象

  3. 对外暴露一个用于获取对象的静态方法

    • 判断对象是否为空

    • 在同步代码块中进行判断, 如果为空就实例化

    • 返回当前对象

(2) 代码实现
package com.itheima._01single.demo04;

/**
 *
 * 懒汉式 - 同步代码块
 *
 *  这种实现方式是有问题的, 我要用这种方式给大家引出最终的BOSS
 *
 *  刚才使用同步方法的时候, 可以保证只创建一个对象, 但是每一次都要先获取锁
 *
 *  1. 不每一次上来就直接先获取锁
 *  2. 等判断完为null, 再获取锁, 创建对象
 *
 */
public class Singleton {
    // 1. 私有构造
    private Singleton() {}
    // 2. 声明引用
    private static Singleton instance;
    // 3. 公共方法
    // 把获取锁对象的时机延后, 且不满足条不会获取锁(减少了获取锁的次数)
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

(3) 优缺点
  • 缺点: 想提高同步方法的效率, 但是又出现了多线程中创建多个对象的问题

实际开发中不能使用

双重检查(Double-Check)【推荐使用】

(1) 实现步骤
  1. 私有构造方法
  2. 类的内部创建对象(使用volatile修饰)
  3. 对外暴露一个用于获取对象的静态方法
    • 判断对象是否为空
    • 同步代码块
    • 在同步代码块中再次判断对象是否为空
    • 如果为空再实例化
    • 最后返回当前对象
(2) 代码实现
package com.itheima._01single.demo05;

/**
 *
 *  双重检查
 *
 *  1. 两个if(instance == null) 的判断
 *  2. 加上volatile关键字, 保证共享数据可可见性
 *
 */
public class Singleton {
    // 1. 私有构造
    private Singleton() {}

    // 2. 声明引用
    private static volatile Singleton instance;

    // 3. 提供获取对象的方法
    public static Singleton getInstance() {
            // 如果对象不存在
            if (instance == null) {

                // 线程1, 判断是null ||  线程2, 判断是null
                // 同步锁
                // 问题: 多线程中有可能创建多个对象
                synchronized (Singleton.class) {
                    if (instance == null) {
                        // 创建对象
                        instance = new Singleton();
                    }
                }
            }

            return instance;
    }
}

(3) 优缺点
  • 进行两次null检查, 可以保证线程安全
  • 实例化的代码只会执行一次, 后面再次访问的时候直接return实例化的对象, 避免了同步的多次执行.
  • 线程安全, 懒加载, 效率较高

总结: 实际开发中, 推荐使用这种单例设计模式

双重检查单例的图解

在这里插入图片描述

多例设计模式

多例模式,是一种常用的软件设计模式。通过多例模式可以保证系统中,应用该模式的类有固定数量的实例。多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法。

实现步骤

​ 1.创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。

​ 2.在类中定义该类被创建的总数量

​ 3.在类中定义存放类实例的list集合

​ 4.在类中提供静态代码块,在静态代码块中创建类的实例

​ 5.提供获取类实例的静态方法

实现代码如下

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Multition {
    // 定义该类被创建的总数量
    private static final int maxCount = 3;
    // 定义存放类实例的list集合
    private static List instanceList = new ArrayList();
    // 构造方法私有化,不允许外界创建本类对象
    private Multition() {
    }
    static {
        // 创建本类的多个实例,并存放到list集合中
        for (int i = 0; i < maxCount; i++) {
            Multition multition = new Multition();
            instanceList.add(multition);
        }
    }
    // 给外界提供一个获取类对象的方法
    public static Multition getMultition(){
        Random random = new Random();
        // 生成一个随机数
        int i = random.nextInt(maxCount);
        // 从list集合中随机取出一个进行使用
        return (Multition)instanceList.get(i);
    }
}

测试结果

public static void main(String[] args) {
    // 编写一个循环从中获取类对象
    for (int i = 0; i < 10; i++) {
        Multition multition = Multition.getMultition();
        System.out.println(multition);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdULCYPu-1607883570994)(imgs/1565598708749.png)]

多例模式可以保证系统中一个类有固定个数的实例, 在实现需求的基础上, 能够提高实例的复用性.

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值