- 单例模式
- 1. 单例设计模式的作用?
- 2. 单例模式的五种实现方式?
- 2.1 饿汉式:
- 2.2 懒汉式
- 2.3 双重检测锁
- 2.3 为什么我们要进行双重检测?
- 2.4 静态内部类
- 2.5 枚举类型
- 3. 怎么解决反射爆破单例?
- 4. 单例对象的应用
- 装饰者设计模式
- 1. 如何实现?
- 1. 使用场景
- 2. 应用场景
- 3. 装饰器的作用和原理
单例设计模式 保证在一个jvm中,该对象只有一个实例存在。
单例模式重点在于在整个系统上共享一些创建时比较耗资源的对象。整个应用只维护一个特定类实例,它被所有组件共同使用。
- 饿汉式:类初始化时创建单例,线程安全
- 懒汉式:创建实例单例的时候在创建,需要考虑线程安全。
- 双重检测锁: 效率高
- 静态内部类:可以同时保证延迟加载和线程安全
- 枚举类型:线程安全和防止反射调用构造器,还提供自动序列化机制,防止反序列化的时候创建新的对象
也就是类加载的时候立即实例化对象,
实现的步骤是先私有化构造方法,对外提供唯一的静态入口方法
package com.wanghaha.desginPattern;
public class SingletonInstance {
// 声明此类型的变量,并实例化,当该类被加载的时候 就完成了实例化并保存在内存中
private final static SingletonInstance instance = new SingletonInstance();
// 私有化所有的构造方法,防止直接通过new关键字实例化
private SingletonInstance(){}
// 对外提供一个获取实例的静态方法
public static SingletonInstance getInstance(){
return instance;
}
}
饿汉式单例设计模式代码中,static变量会在类加载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机只会装载一次该类,肯定不会发生并发访问的问题。因此可以省略synchronized关键字。
存在问题: 如果只是加载本类,而不是调用getIntance(),甚至永远没有调用,则会造成资源的浪费
2.2 懒汉式线程不安全,多个线程可能同时创建实例对象。
性能不太好。
package com.wanghaha.desginPattern;
public class SingletonInstance2 {
// 声明此类型的变量,并没有实例化
private static SingletonInstance2 instance = null;
// 私有化所有的构造方法,防止直接通过new关键字实例化
private SingletonInstance2(){}
// 对外提供一个获取实例的静态方法,为了数据安全添加synchronized关键字
public static synchronized SingletonInstance2 getInstance(){
if(instance == null){
// 当 instance不为空的时候才实例化
instance = new SingletonInstance2();
}
return instance;
}
}
此种方式在类加载后如果我们一直没有调用getlnstance方法,那么就不会实例化对象。
实现了延迟加载,但是因为在方法上添加了synchronized关键字,每次调用getinstance方法都会同步,所以对性能的影响比较大。
volatile关键字:作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
同步块:锁的是共享资源。
package com.wanghaha.desginPattern;
public class SingletonInstance3 {
// 声明此类型的变量,并没有实例化
private static volatile SingletonInstance3 instance = null;
// 私有化所有的构造方法,防止直接通过new关键字实例化
private SingletonInstance3(){}
// 对外提供一个获取实例的静态方法
public static SingletonInstance3 getInstance(){
if(instance == null){
synchronized (SingletonInstance3.class){
if(instance == null){
// 1. 分配内存空间
// 2. 执行构造方法,实例化对象
// 3. 把这个对象赋值给这个空间
// 如果不加volatile关键字, 会执行重排序 1 3 2
instance = new SingletonInstance3();
}
}
}
return instance;
}
}
2.3 为什么我们要进行双重检测?
2.4 静态内部类
package com.wanghaha.desginPattern;
public class SingletonInstance4 {
// 静态内部类
public static class SingletonClassInstance{
// 声明外部类型的静态变量
public static final SingletonInstance4 instance = new SingletonInstance4();
}
// 私有化所有的构造方法,防止直接通过new关键字实例化
private SingletonInstance4(){}
// 对外提供一个获取实例的静态方法
public static SingletonInstance4 getInstance(){
return SingletonClassInstance.instance;
}
}
2.5 枚举类型
3. 怎么解决反射爆破单例?
解决的方法在 无参构造方法中手动抛出异常机制控制,或者声明一个全局变量来控制
private SingletonInstance3() {
//私有化所有的构造方法,防止直接通过new关键字实例化
if (instance != null) {
//只能有一个实例存在,加果再次调用该构造方法就抛出异常,防止反射方式实例化
throw new RuntimeException("单例模式只能创建一个对象");
}
}
但是还可以通过序列化和反序列化进行破解。
解决方法:重写readResolve方法,直接返回该方法指定的对象。
数据库连接池的设计
java.lang.runtime
装饰者设计模式:给对象动态增加新的功能,需要持有对象实例。
1. 如何实现?装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
package com.wanghaha.desginPattern;
public class DecoratorPattern {
public static void main(String[] args) {
new RobotDecorator(new FirstRobot()).doMoreThion();
}
}
interface Robot{
void doSomethion();
}
class FirstRobot implements Robot{
@Override
public void doSomethion() {
System.out.println("对话");
System.out.println("唱歌");
}
}
class RobotDecorator implements Robot{
private Robot robot;
public RobotDecorator(Robot robot){
this.robot = robot;
}
@Override
public void doSomethion() {
robot.doSomethion();
}
public void doMoreThion(){
robot.doSomethion();
System.out.println("跳舞,拖地");
}
}
1. 使用场景
1、霊要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
BufferedInputStream
python的装饰器
装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能



