首页 > 其他分享 >3) Singleton pattern

3) Singleton pattern

时间:2023-06-06 13:36:34浏览次数:39  
标签:Singleton instance pattern INSTANCE Demo1 static new class

类别:

creational Pattern

问题/动机:

反复创建对象开销巨大耗时长消耗内存/重复使用

方案:

 

 

示例:

 

// 1
class Demo1 {
    public final static Demo1 INSTANCE = new Demo1();

    private Demo1() {
        if (INSTANCE != null)
            throw new RuntimeException("Singleton instance alread exist.");
    }
}

// 2
class Demo2 {
    private final static Demo2 INSTANCE = new Demo2();

    private Demo2() {
        if (INSTANCE != null)
            throw new RuntimeException("Singleton instance alread exist.");
    }

    public static Demo2 getInstance() {
        return INSTANCE;
    }
}

// 3
class Demo3 {
    private static volatile Demo3 INSTANCE;

    private Demo3() {
        if (INSTANCE != null)
            throw new RuntimeException("Singleton instance alread exist.");
    }

    public static Demo3 getInstance() {
        if (INSTANCE != null)
            return INSTANCE;
        synchronized (Demo3.class) {
            if (INSTANCE == null)
                INSTANCE = new Demo3();
        }
        return INSTANCE;
    }
}

// 4
enum Demo4 {
    INSTANCE;
}

 

①/② 同理,饿汉加载(tips:类加载机制线程安全,不能延迟加载,不需要同步效率高)

③ 懒汉加载

④ 最优方式

⑤ 静态内部类(安全,可延迟)

击破:

 1. 反序列化击破单例

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SingletonDemo {
    public static void main(String[] args) throws Exception {
        Demo1 instance = Demo1.INSTANCE;
        // 存储到 demo1_serializable 文件
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream("demo1_serializable"));
        oo.writeObject(instance);
        oo.close();
        
        // 从 demo1_serializable 反序列化
        ObjectInputStream oi = new ObjectInputStream(new FileInputStream("demo1_serializable"));
        Object readObject = oi.readObject();
        oi.close();
        
        // 结果是 false ,通过反序列化击破了单例模式 
        System.out.println(instance == readObject);
    }
}

class Demo1 implements Serializable {
    private static final long serialVersionUID = 1L;
    public final static Demo1 INSTANCE = new Demo1();

    private Demo1() {
        if (INSTANCE != null)
            throw new RuntimeException("Singleton instance alread exist.");
    }
}

弥补: 不实现序列化接口,或者不采用 ①/②/③

2. 通过 Clone 击破单例

public class SingletonDemo {
    public static void main(String[] args) {
        Demo1 instance = Demo1.INSTANCE;
        Demo1 clone = instance.clone();

        // 结果是 false ,通过克隆击破了单例模式
        System.out.println(instance == clone);
    }
}

class Demo1 implements Cloneable {
    public final static Demo1 INSTANCE = new Demo1();

    private Demo1() {
        if (INSTANCE != null)
            throw new RuntimeException("Singleton instance alread exist.");
    }

    @Override
    public Demo1 clone() {
        try {
            return (Demo1) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("Clone not supported");
        }
    }
}

弥补:不实现Cloneable 接口,或者不采用①/②/③

3. 通过反射击破单例

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class SingletonDemo {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Demo1 instance = Demo1.INSTANCE;

        Constructor<Demo1> declaredConstructor = Demo1.class.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Demo1 newInstance = declaredConstructor.newInstance();

        // 结果是 false ,通过反射击破了单例模式
        System.out.println(instance == newInstance);
    }
}

class Demo1 {
    public final static Demo1 INSTANCE = new Demo1();

    private Demo1() {
    }
}

弥补: 在构造函数中判断,如果实例已经存在,则抛出异常

    private Demo1() {
        if (INSTANCE != null)
            throw new RuntimeException("Singleton instance alread exist.");
    }

 

4. 通过枚举类型强化单例模式

1) 反射找不到方法 java.lang.NoSuchMethodException:

2)无法覆盖 clone 方法

3)自带序列化,反序列化后是同一个对象

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SingletonDemo {
    public static void main(String[] args) throws Exception {
        Demo1 instance = Demo1.INSTANCE;
        // 存储到 demo1_serializable 文件
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream("demo1_serializable"));
        oo.writeObject(instance);
        oo.close();

        // 从 demo1_serializable 反序列化
        ObjectInputStream oi = new ObjectInputStream(new FileInputStream("demo1_serializable"));
        Object readObject = oi.readObject();
        oi.close();

        // 结果是 true ,通过枚举强化了单例模式
        System.out.println(instance == readObject);
    }
}

enum Demo1 {
    INSTANCE;
}

 

应用:

数据库连接池?

servlet?

Spring MVC controller ?

 

类加载机制如何保证线程安全?

 

补充:

//5
class Demo5{
    
    private Demo5(){
        throw new RuntimeException("Singleton instance alread exist.");
    }
    
    private static class Inner{
        private static Demo5 demo5 = new Demo5();
    }
    
    public static Demo5 getInstance(){
        return Inner.demo5;
    }
}

 

https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class. As a member of the OuterClass, a nested class can be declared privatepublicprotected, or package private. (Recall that outer classes can only be declared public or package private.)

Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

标签:Singleton,instance,pattern,INSTANCE,Demo1,static,new,class
From: https://www.cnblogs.com/zno2/p/6694803.html

相关文章

  • 2) Abstract Factory Pattern
    类别: CreationalPattern问题/动机:如何创建一套父类的问题情形一:混淆,且不能察觉//下面这个方法本来是要建造一辆宝马汽车,但是因为零部件太多,粗心大意误用了奔驰的零件。publicCarcreateBMWCar(){Part1p1=newcom.bmw.Part1();[...]......
  • 1) Factory method pattern
    类别: CreationalPattern问题/动机如何创建一套子类的问题(父类引用指向子类实例)情形1:一个方法返回一个具体的子类极端情况:1万个子类需要一万个方法吗极端情况:如过再扩展一万个子类,还需要再增加一万个方法吗极端情况:虽然有一万个子类,但只需要用到其中一个,其他9999个干陪着......
  • 9) Composite Pattern
    类别: StructualPattern问题: 方案:   示例: importjava.util.ArrayList;importjava.util.List;publicclassCompositePatternDemo{publicstaticvoidmain(String[]args){Bodysun=newBody("太阳","恒星",1392000000);......
  • 8) Filter/Criteria Pattern
    类别: StructualPattern问题: 方案:   示例: importjava.util.ArrayList;importjava.util.HashSet;importjava.util.List;importjava.util.Set;publicclassCriteriaPatternDemo{publicstaticvoidmain(String[]args){List<Person>p......
  • 7) Bridge Pattern
    类别: StructuralPatterns问题:连连看的问题 不使用桥接,要写81个类,使用桥接,只需要18个类方案: 示例: publicclassBridgePatternDemo{publicstaticvoidmain(String[]args){Somebodysb=newXiaohong(newBanana());sb.eat();......
  • 6) Adapter Pattern
    类别: StructuralPattern问题:什么是接口?按照标准提供服务,其他想要使用该接口的要按照该标准接入服务什么是依赖?持有目标对象,拥有使用权(AuseB)数据线?数据线按USB标准接入充电宝,通过lightning提供充电服务手机?通过lightning标准接入数据线  客户端因种种限制只能接入......
  • 10) Decorator Pattern
    类别: StructuralPattern问题: 在不改变接口的前提下增加额外的服务方案:   示例:publicclassDecoratorPatternDemo{publicstaticvoidmain(String[]args){Shapecircle=newCircle();ShaperedCircle=newRedShapeDecorator(newC......
  • cpp: Bridge Pattern
     /*****************************************************************//***\fileGold.h*\brief桥接模式BridgePatternC++14*2023年6月3日涂聚文GeovinDuVisualStudio2022edit.*\authorgeovindu*\dateJune2023***********************......
  • log4j2<PatternLayout>子节点浅析
    log4j2<PatternLayout>子节点浅析 首先声明本文并不教您怎么用log4j2,仅仅只对<PatternLayout>子节点进行说明。要看懂本文需要对log4j2有一定的了解,至少能够知道<Appenders>、<Layouts>和<Loggers>的区别。本文主要参考对象为log4j2官方手册:《ApacheLog4j2v.2.1User'sGuide......
  • cpp: Proxy Pattern
     /*****************************************************************//***\fileGoldWebSite.h*\brief代理模式ProxyPatternC++14*2023年5月31日涂聚文GeovinDuVisualStudio2022edit.*\authorgeovindu*\dateMay2023******************......