设计模式之单例模式

单例模式

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

引子:读取配置文件

很多地方要用到,如果每次都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

相关推荐
Damon_X1 小时前
桥接模式(Bridge Pattern)
设计模式·桥接模式
越甲八千5 小时前
重温设计模式--享元模式
设计模式·享元模式
码农爱java6 小时前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式
越甲八千7 小时前
重温设计模式--中介者模式
windows·设计模式·中介者模式
犬余7 小时前
设计模式之桥接模式:抽象与实现之间的分离艺术
笔记·学习·设计模式·桥接模式
Theodore_10228 小时前
1 软件工程——概述
java·开发语言·算法·设计模式·java-ee·软件工程·个人开发
越甲八千10 小时前
重拾设计模式--组合模式
设计模式·组合模式
思忖小下13 小时前
梳理你的思路(从OOP到架构设计)_设计模式Composite模式
设计模式·组合模式·eit
机器视觉知识推荐、就业指导13 小时前
C++设计模式:组合模式(公司架构案例)
c++·后端·设计模式·组合模式
越甲八千13 小时前
重拾设计模式--工厂模式(简单、工厂、抽象)
c++·设计模式