笨蛋学设计模式创建者模式-单例模式【2】

创建者模式-单例模式

    • 6.1单例模式:arrow_up::arrow_up::arrow_up:
      • 6.1.1概念
      • 6.1.2场景
      • 6.1.3优势 / 劣势
      • 6.1.4满足单例模式的基本要求
        • 私有的构造函数:防止外部代码直接创建类的实例
        • 私有的静态实例变量:保存该类的唯一实例
        • 公有的静态方法:通过公有的静态方法来获取类的实例
      • 6.1.5饿汉式
      • 6.1.6懒汉式
      • 6.1.7懒汉式+双重检查锁
      • 6.1.8实战
        • 6.1.8.1题目描述
        • 6.1.8.2输入描述
        • 6.1.8.3输出描述
        • 6.1.5.4代码
      • 6.1.9总结
      • 饿汉式
      • 懒汉式


6.1单例模式⬆️⬆️⬆️

6.1.1概念

​ 单例模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例,通常用于需要频繁创建和销毁同一对象的场景,以避免资源浪费和提高性能。

6.1.2场景

​ 我们只有一个大脑,但是我们需要频繁地使用它来思考、记忆和判断。如果我们每次需要使用大脑时都重新创建一个新的大脑,那么就会浪费时间以及其他资源。因此,我们只需要一个大脑实例,并通过全局访问点(例如我们的嘴巴和眼睛)来使用它。

6.1.3优势 / 劣势

  • 全局访问点:确保所有对象都能访问到唯一实例,避免了创建多个对象实例
  • 线程安全:单例模式可以保证线程安全,避免多线程下对共享资源的竞争问题,确保数据一致性和线程安全性
  • 资源节省:确保程序中存在一个实例,避免了多次创建和销毁同一对象,减少了系统资源的浪费

  • 过度依赖单例:可能会导致各个模块之间的耦合度过高,不利于代码的模块化和可维护性
  • 不适用多实例场景:若需要多个实例来执行不同的任务,就无法满足任务
  • 生命周期过长:单例模式的生命周期往往贯穿整个应用程序的始终,可能会导致一些其他问题

6.1.4满足单例模式的基本要求

  • 私有的构造函数:防止外部代码直接创建类的实例
  • 私有的静态实例变量:保存该类的唯一实例
  • 公有的静态方法:通过公有的静态方法来获取类的实例

6.1.5饿汉式

  • 在类加载时就已经完成了实例的创建,不管后面创建的实例有没有使用,先创建再说,所以称之为饿汉
public class Hungry {
    
    private static final Hungry instance = new Hungry();
    
    private Hungry(){
        //私有化构造方法,防止外部实例化
    }
    
    public static Hungry getInstance(){
        return instance;
    }
}

6.1.6懒汉式

  • 在请求实例时才会创建,若在首次请求时还没有创建,就创建一个新的实例,若已经创建就返回已有的实例,需要使用再创建,所以称之为懒汉
public class Lazy {

    private static Lazy instance;

    private Lazy(){
        //私有化构造方法,防止外部实例化
    }

    public static synchronized Lazy getInstance(){
        if(instance == null){
            instance = new Lazy();
        }
        return instance;
    }
}

6.1.7懒汉式+双重检查锁

public class LazyAndLock {
    private static volatile LazyAndLock instance;

    private LazyAndLock(){
        //私有构造方法,防止外部实例化
    }

    public static LazyAndLock getInstance(){
        if(instance == null){
            //LazyAndLock.class作为同步锁对象,保证多线程环境下只有一个线程进入同步块内部创建对象
            synchronized (LazyAndLock.class){
                if(instance == null){
                    instance = new LazyAndLock();
                }
            }
        }
        return instance;
    }
}

6.1.8实战

6.1.8.1题目描述

小明去了一家大型商场,拿到了一个购物车,并开始购物。请你设计一个购物车管理器,记录商品添加到购物车的信息(商品名称和购买数量),并在购买结束后打印出商品清单。(在整个购物过程中,小明只有一个购物车实例存在)。

6.1.8.2输入描述

输入包含若干行,每行包含两部分信息,分别是商品名称和购买数量。商品名称和购买数量之间用空格隔开。

6.1.8.3输出描述

输出包含小明购物车中的所有商品及其购买数量。每行输出一种商品的信息,格式为 “商品名称 购买数量”。

6.1.5.4代码

饿汉式

package com.designpattern.mode.singleton;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class Test {
    public static void main(String[] args) {
        HungryShoppingCartManager cart = HungryShoppingCartManager.getInstance();

        Scanner scanner = new Scanner(System.in);

        while (scanner.hasNext()){
            String goods = scanner.next();
            int goodsNum = scanner.nextInt();

            //添加到购物车
            cart.addCart(goods,goodsNum);
        }

//        cart.delCart("apple");
//
//        cart.updCart("banana",3);

        //查找所有的商品
        cart.selCart();

    }
}

class HungryShoppingCartManager{
    //使用购物车前就创建
    private static HungryShoppingCartManager instance=new HungryShoppingCartManager();

    //定义购物车存放商品及对应的数量
    private Map<String,Integer> cart;

    private HungryShoppingCartManager(){
        //私有化构造方法,防止外部实例化
        cart = new LinkedHashMap<>();
    }

    public static HungryShoppingCartManager getInstance(){
        return instance;
    }

    //定义添加方法
    public void addCart(String goods,int goodsNum){
        //getOrDefault(goods, 0) 方法获取该物品的数量,如果获取不到则返回默认值 0
        cart.put(goods,cart.getOrDefault(goods,0)+goodsNum);
    }

    //定义删除方法
    public void delCart(String goods){
        cart.remove(goods);
    }

    //定义修改方法
    public void updCart(String goods,int goodsNum){
        cart.put(goods,goodsNum);
    }

    //定义查找方法
    public void selCart(){
        Set<Map.Entry<String, Integer>> entrySet = cart.entrySet();

        for (Map.Entry<String, Integer> entry : entrySet) {
            String key = entry.getKey();
            int value = entry.getValue();
            System.out.println(key+"-"+value);
        }
    }
}


懒汉式+双重检查锁

package com.designpattern.mode.singleton;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class Test {

    public static void main(String[] args) {

        LazyShoppingCartManager cart = LazyShoppingCartManager.getInstance();

        Scanner scanner = new Scanner(System.in);

        while (scanner.hasNext()){
            String goods = scanner.next();
            int goodsNum = scanner.nextInt();

            //添加到购物车
            cart.addCart(goods,goodsNum);
        }

//        cart.delCart("apple");
//
//        cart.updCart("banana",3);

        //查找所有的商品
        cart.selCart();
    }
}

class LazyShoppingCartManager{
    private static LazyShoppingCartManager instance;

    //购物车存放商品及对应数量
    private Map<String,Integer> cart;

    //私有化构造函数
    private LazyShoppingCartManager(){
        cart = new LinkedHashMap<>();
    }

    //获取购物车实例
    public static synchronized LazyShoppingCartManager getInstance(){
        if(instance == null){
            synchronized (LazyShoppingCartManager.class){
                if(instance == null){
                    instance = new LazyShoppingCartManager();
                }
            }
        }
        return instance;
    }

    //定义添加方法
    public void addCart(String goods,int goodsNum){
        //getOrDefault(goods, 0) 方法获取该物品的数量,如果获取不到则返回默认值 0
        cart.put(goods,cart.getOrDefault(goods,0)+goodsNum);
    }

    //定义删除方法
    public void delCart(String goods){
        cart.remove(goods);
    }

    //定义修改方法
    public void updCart(String goods,int goodsNum){
        cart.put(goods,goodsNum);
    }

    //定义查找方法
    public void selCart(){
        Set<Map.Entry<String, Integer>> entrySet = cart.entrySet();

        for (Map.Entry<String, Integer> entry : entrySet) {
            String key = entry.getKey();
            int value = entry.getValue();
            System.out.println(key+"-"+value);
        }
    }

}


6.1.9总结

  • 饿汉式

优点:在类加载时就完成了初始化,避免了线程同步的问题,是最安全的单例模式实现方式

总结:在类加载时就实例化了一个对象,所以类加载较慢,但获取对象的速度快

场景:主要用于线程安全的场景

  • 懒汉式

优点:只有在需要对象时才会进行实例化,具有更好的灵活性。

总结:在类加载时不进行实例化,当调用getInstance方法时才进行实例化。

场景:主要用于线程不安全的场景,可以使用双重检查锁定等方法来保证线程安全。

你可能感兴趣的:(笨蛋学设计模式,设计模式,java,单例模式)