盖个楼还要有图纸,你怎么可以不懂设计模式(二)

前序:

相关引读

模板方法模式&观察者模式&责任链模式

传送门: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

 

posted @ 2020-10-18 22:49  powerZhangFly  阅读(105)  评论(0)    收藏  举报