单例模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例,通常用于需要频繁创建和销毁同一对象的场景,以避免资源浪费和提高性能。
我们只有一个大脑,但是我们需要频繁地使用它来思考、记忆和判断。如果我们每次需要使用大脑时都重新创建一个新的大脑,那么就会浪费时间以及其他资源。因此,我们只需要一个大脑实例,并通过全局访问点(例如我们的嘴巴和眼睛)来使用它。
public class Hungry {
private static final Hungry instance = new Hungry();
private Hungry(){
//私有化构造方法,防止外部实例化
}
public static Hungry getInstance(){
return instance;
}
}
public class Lazy {
private static Lazy instance;
private Lazy(){
//私有化构造方法,防止外部实例化
}
public static synchronized Lazy getInstance(){
if(instance == null){
instance = new Lazy();
}
return instance;
}
}
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;
}
}
小明去了一家大型商场,拿到了一个购物车,并开始购物。请你设计一个购物车管理器,记录商品添加到购物车的信息(商品名称和购买数量),并在购买结束后打印出商品清单。(在整个购物过程中,小明只有一个购物车实例存在)。
输入包含若干行,每行包含两部分信息,分别是商品名称和购买数量。商品名称和购买数量之间用空格隔开。
输出包含小明购物车中的所有商品及其购买数量。每行输出一种商品的信息,格式为 “商品名称 购买数量”。
饿汉式
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);
}
}
}
优点:在类加载时就完成了初始化,避免了线程同步的问题,是最安全的单例模式实现方式
总结:在类加载时就实例化了一个对象,所以类加载较慢,但获取对象的速度快
场景:主要用于线程安全的场景
优点:只有在需要对象时才会进行实例化,具有更好的灵活性。
总结:在类加载时不进行实例化,当调用getInstance方法时才进行实例化。
场景:主要用于线程不安全的场景,可以使用双重检查锁定等方法来保证线程安全。