设计模式之单例模式

单例模式

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点

引子:读取配置文件

很多地方要用到,如果每次都new 一个对象的话,会浪费内存资源。

改装成饿汉式(饿汉式有线程并发问题,懒汉式没有)

也可以完成需求,但是节约资源了?因为只有一个地方去使用,也见不到效果

场景:需要读取配置,这个用途在开发中是很常见的。

package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * @Author Mi_Tao
 * @Date 2023/7/23
 * @Description
 * @Version 1.0
 **/
public class AppConfig {

    private String parameterA;
    private String parameterB;

    public AppConfig(){
        readConfig();
    }

    private void readConfig() {
        Properties properties = new Properties();
        InputStream in = null;

        try {
            in = AppConfig.class.getResourceAsStream("/Appconfig.properties");
            properties.load(in);
            // 把配置文件中的内容读出来设置到属性上
            this.parameterA = properties.getProperty("parameterA");
            this.parameterB = properties.getProperty("parameterB");
        } catch (IOException e) {
            System.out.println("转载配置文件出错了!");
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String getParameterA() {
        return parameterA;
    }

    public String getParameterB() {
        return parameterB;
    }
}

配置类位置

直接的做法,读取文件

package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;

/**
 * @Author Mi_Tao
 * @Date 2023/7/23
 * @Description
 * @Version 1.0
 **/
public class Client {

    public static void main(String[] args) {
        // 创建读取应用的配置对象
        AppConfig config = new AppConfig();
        String parameterA = config.getParameterA();
        System.out.println("parameterA = " + parameterA);
        String parameterB = config.getParameterB();
        System.out.println("parameterB = " + parameterB);
    }
}

这种方式:快捷。但是如果但很多的类都需要使用到这些配置,就会大量new 出重复的对象,造成资源浪费!!

解决方法:既然这些配置都是一样的,我们其实只需要一个实例就行。所以我们可以使用单例模式
而常见单例的方法也是多样的:

1、饿汉式

package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;

/**
 * 饿汉式
 *
 * @Author Mi_Tao
 * @Date 2023/7/23
 * @Description
 * @Version 1.0
 **/
public class HungrySingleton {

    //定义一个变量来存储创建好的类实例,只能创建一次
    private static HungrySingleton uniqueInstance = new HungrySingleton();

    /**
     * 构造私有化方法,可以再内部控制创建实例的数目
     */
    private static HungrySingleton getInstance() {
        // 直接使用创建好的实例
        return uniqueInstance;
    }



    /**
     * 单例可以有自己的操作
     */
    public void singletonOperation(){

    }

    public String getSingletonData() {
        return singletonData;
    }

    // 属性,单例可以有自己的属性
    private String singletonData;




}

2、懒汉式

package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;

/**
 * 懒汉式
 *
 * @Author Mi_Tao
 * @Date 2023/7/23
 * @Description
 * @Version 1.0
 **/
public class LazySingleton {

    //定义一个变量来存储创建好的类实例
    private static LazySingleton uniqueInstance = null;

    /**
     * 构造私有化方法,可以再内部控制创建实例的数目
     */
    private LazySingleton() {
    }

    /**
     * 获取单例
     *
     * @return {@link LazySingleton}
     */
    public static synchronized LazySingleton getSingleton(){
        // 判断存储实例的变量是否有值
        if (uniqueInstance == null){
            // 如果没有,就创建一个
            uniqueInstance = new LazySingleton();
        }
        // 否则直接返回
        return uniqueInstance;
    }

    /**
     * 单例可以有自己的操作
     */
    public void singletonOperation(){

    }

    public String getSingletonData() {
        return singletonData;
    }

    // 属性,单例可以有自己的属性
    private String singletonData;




}

测试

package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;

/**
 * @Author Mi_Tao
 * @Date 2023/7/23
 * @Description
 * @Version 1.0
 **/
public class ClientV2_Hungry {

    public static void main(String[] args) {
        // 创建读取应用的配置对象
        AppConfigV2_Hungry config = AppConfigV2_Hungry.getInstance();
        String parameterA = config.getParameterA();
        System.out.println("parameterA = " + parameterA);
        String parameterB = config.getParameterB();
        System.out.println("parameterB = " + parameterB);
    }
}

懒汉式。从名字不难理解。在需要使用的使用才会去创建,而不去创建就不去创建。但是会有并发问题。

并发问题的解决,我们可以使用双检锁来升级一下,解决问题

package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;

/**
 * 懒汉式
 *
 * @Author Mi_Tao
 * @Date 2023/7/23
 * @Description 考虑并发时候的单例 双检锁
 * @Version 1.0
 **/
public class LazySingleton_current {

    //定义一个变量来存储创建好的类实例  内存屏障去掉,直接访问共享内存
    private volatile static LazySingleton_current uniqueInstance = null;

    /**
     * 构造私有化方法,可以再内部控制创建实例的数目
     */
    private LazySingleton_current() {
    }

    /**
     * 获取单例
     *
     * @return {@link LazySingleton_current}
     */
    public static synchronized LazySingleton_current getSingleton(){
        // 判断存储实例的变量是否有值
        if (uniqueInstance == null){
            synchronized (LazySingleton_current.class){
                if (uniqueInstance == null){
                    // 如果没有,就创建一个
                    uniqueInstance = new LazySingleton_current();
                }
            }
        }
        // 否则直接返回
        return uniqueInstance;
    }

    /**
     * 单例可以有自己的操作
     */
    public void singletonOperation(){

    }

    public String getSingletonData() {
        return singletonData;
    }

    // 属性,单例可以有自己的属性
    private String singletonData;




}

tips

使用枚举类也可以实现单例

本文参考:《研磨设计模式》

相关代码: https://gitee.com/zitaoyang/design-mode

相关推荐
nakyoooooo27 分钟前
【设计模式】工厂模式、单例模式、观察者模式、发布订阅模式
观察者模式·单例模式·设计模式
严文文-Chris2 小时前
【设计模式-享元】
android·java·设计模式
丶白泽3 小时前
重修设计模式-设计原则
设计模式·接口隔离原则·依赖倒置原则·开闭原则
【D'accumulation】3 小时前
典型的MVC设计模式:使用JSP和JavaBean相结合的方式来动态生成网页内容典型的MVC设计模式
java·设计模式·mvc
仙魁XAN4 小时前
Unity 设计模式 之 创造型模式-【工厂方法模式】【抽象工厂模式】
unity·设计模式·工厂方法模式·抽象工厂模式
龙哥·三年风水14 小时前
活动系统开发之采用设计模式与非设计模式的区别-后台功能总结
设计模式·php·tinkphp6
一头老羊15 小时前
前端常用的设计模式
设计模式
严文文-Chris16 小时前
【设计模式-组合】
设计模式
Magnetic_h16 小时前
【iOS】单例模式
笔记·学习·ui·ios·单例模式·objective-c
kimloner17 小时前
工厂模式(二):工厂方法模式
java·设计模式·工厂方法模式