盖个楼还要有图纸,你怎么可以不懂设计模式(二)
前序:
相关引读
模板方法模式&观察者模式&责任链模式
传送门:https://www.cnblogs.com/powerZhangFly/p/13800875.html
正文:
单例设计模式&工厂方法模式
单例设计模式
模式定义:
保证一个类只有一个实例,并且提供一个全局访问点
场景:
重量级的对象,不需要多个实例,如线程池,数据库连接池。
1.懒汉模式:
延迟加载, 只有在真正使用的时候,才开始实例化。
1)线程安全问题
2)double check 加锁优化
3)编译器(JIT),CPU 有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile 关键字进行修饰,对于volatile 修饰的字段,可以防止指令重排。
1class LazySingleton{ 2 private volatile static LazySingleton instance; 3 private LazySingleton(){ 4 5 } 6 public static LazySingleton getInstance() { 7 if (instance==null){ 8 synchronized (LazySingleton.class){ 9 if (instance==null){ 10 instance=new LazySingleton(); 11 // 字节码层 12 // JIT , CPU 有可能对如下指令进行重排序 13 // 1 .分配空间 14 // 2 .初始化 15 // 3 .引用赋值 16 // 如重排序后的结果为如下 17 // 1 .分配空间 18 // 3 .引用赋值 如果在当前指令执行完,有其他线程来获取实例,将拿到尚未初始化好的 实例 19 // 2 .初始化 20 21 22 } 23 } 24 25 } 26 return instance; 27 } 28 }
2.饿汉模式:
类加载的 初始化阶段就完成了 实例的初始化 。本质上就是借助于jvm类加载机制,保证实例的唯一性(初始化过程只会执行一次)及线程安全(JVM以同步的形式来完成类加载的整个过程)。
类加载过程:
1,加载二进制数据到内存中, 生成对应的Class数据结构,
2,连接: a. 验证, b.准备(给类的静态成员变量赋默认值),c.解析
3,初始化: 给类的静态变量赋初值
只有在真正使用对应的类时,才会触发初始化 如( 当前类是启动类即main函数所在类,直接进行new 操作,访问静态属性、访问静态方法,用反射访问类,初始化一个类的子类等.)
1// 饿汉模式 2 3 class HungrySingleton{ 4 private static HungrySingleton instance=new HungrySingleton(); 5 private HungrySingleton(){ 6 } 7 public static HungrySingleton getInstance() { 8 return instance; 9 } 10 }
3.静态内部类
1).本质上是利用类的加载机制来保证线程安全
2).只有在实际使用的时候,才会触发类的初始化,所以也是懒加载的一种形式。
1 class InnerClassSingleton{ 2 3 private static class InnerClassHolder{ 4 private static InnerClassSingleton instance= new InnerClassSingleton(); 5 } 6 private InnerClassSingleton(){ 7 8 } 9 public static InnerClassSingleton getInstance(){ 10 return InnerClassHolder.instance; 11 } 12 }
4.反射攻击实例:
1 Constructor<InnerClassSingleton> declaredConstructor=InnerClassSingleton.c lass.getDeclaredConstructor(); 2 declaredConstructor.setAccessible( true ); 3 InnerClassSingleton innerClassSingleton=declaredConstructor.newInstance(); 4 5 InnerClassSingleton instance=InnerClassSingleton.getInstance(); 6 System.out.println(innerClassSingleton==instance);
静态内部类防止反射破坏
1 class InnerClassSingleton { 2 3 4 private static class InnerClassHolder{ 5 private static InnerClassSingleton instance= new InnerClassSingleton(); 6 } 7 private InnerClassSingleton(){ 8 9 if (InnerClassHolder.instance!=null){ 10 throw new RuntimeException( " 单例不允许多个实例 " ); 11 } 12 13 } 14 public static InnerClassSingleton getInstance(){ 15 return InnerClassHolder.instance; 16 } 17 }
5.枚举类型
1)天然不支持反射创建对应的实例,且有自己的反序列化机制
2)利用类加载机制保证线程安全
1 public enum EnumSingleton { 2 INSTANCE; 3 4 public void print(){ 5 System.out.println(this.hashCode()); 6 } 7 }
6.序列化
1)可以利用 指定方法来替换从反序列化流中的数据 如下
1 ANY‐ACCESS‐MODIFIER Object readResolve() throws ObjectStreamException;
1 class InnerClassSingleton implements Serializable{ 2 3 static final long serialVersionUID = 42L; 4 5 private static class InnerClassHolder{ 6 private static InnerClassSingleton instance= new InnerClassSingleton(); 7 } 8 private InnerClassSingleton(){ 9 10 if (InnerClassHolder.instance!=null){ 11 throw new RuntimeException( " 单例不允许多个实例 " ); 12 } 13 14 } 15 public static InnerClassSingleton getInstance(){ 16 return InnerClassHolder.instance; 17 } 18 19 Object readResolve() throws ObjectStreamException{ 20 return InnerClassHolder.instance; 21 } 22 23 }
源码中的应用
1 // Spring & JDK 2 java.lang.Runtime 3 org.springframework.aop.framework.ProxyFactoryBean 4 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry 5 org.springframework.core.ReactiveAdapterRegistry 6 // Tomcat 7 org.apache.catalina.webresources.TomcatURLStreamHandlerFactory 8 // 反序列化指定数据源 9 java.util.Currency
工厂方法模式
模式定义:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod 使得一个类的实例化延迟到子类
简单工厂:
1 class SimpleFactory { 2 public static Product createProdcut(String type) { 3 if (type.equals( "0" )) { 4 return new ProductA(); 5 } else if (type.equals( "1" )) { 6 return new ProductA1(); 7 } else { 8 return null; 9 } 10 } 11 }
工厂方法:
1 // 稳定接口 2 interface Product { 3 public void method1(); 4 } 5 // 具体实现 6 class ProductA implements Product { 7 8 public void method1() { 9 System.out.println( "ProductA.method1 executed. " ); 10 } 11 } 12 13 class ProductA1 implements Product { 14 15 public void method1() { 16 System.out.println( "ProductA1.method1 executed. " ); 17 } 18 } 19 20 21 22 abstract class Application { 23 24 abstract Product createProduct(); 25 26 Product getObject() { 27 Product product=createProduct(); 28 // ... 29 // ... 30 return product; 31 } 32 33 } 34 // 工厂方法具体实现类 35 class ConcreteProductA extends Application { 36 @Override 37 Product createProduct() { 38 // .... 39 return new ProductA(); 40 } 41 } 42 43 class ConcreteProductA1 extends Application { 44 @Override 45 Product createProduct() { 46 //... 47 return new ProductA1(); 48 } 49 }
应用场景
1.当你不知道改使用对象的确切类型的时候
2.当你希望为库或框架提供扩展其内部组件的方法时
主要优点:
1.将具体产品和创建者解耦2.符合单一职责原则
3.符合开闭原则
源码中的应用:
1 // java api 2 // 静态工厂方法 3 4 Calendar.getInstance() 5 java.text.NumberFormat.getInstance() 6 java.util.ResourceBundle.getBundle() 7 8 // 工厂方法 9 java.net.URLStreamHandlerFactory 10 javax.xml.bind.JAXBContext.createMarshaller

浙公网安备 33010602011771号