学习目标:
Java中设计模式
掌握单例模式
学习内容:
六大原则:
- SRP:单一职责原则 一个类只做一件事
- LSP:里氏替换原则 不要破坏继承体系
- DIP:依赖倒置原则 面向接口编程
- ISP:接口隔离原则 设计接口的时候要精简单一
- LOD:迪米特原则 降低耦合
- OCP:开闭原则 扩展开放 修改关闭
总之六大原则:高内聚低耦合;增加我们代码的维护性,当我们单一需求确定后不会因为增加新的需求而影响带原有已经确定的类;面向抽象,不面向实现编程
工厂模式:
- 个人理解就是在业务代码中需要switch case 判断逻辑;针对不同的case我们需要不同的实现类,业务方法我们就可以在上面再封装一层工厂,工厂来处理业务逻辑;调用放不需要自己判断
- 当我们增加了新的需求时需要添加新的业务类的时候可能需要修改工厂中的判断逻辑,为了解决这个问题我们可以将工厂再封装一层,实现接口;也就是我们会针对多个实现类有不同的工厂;抽象工厂-->具体工厂类--->抽象业务-->具体业务类
- 针对此工厂新的需求产生:根据抽象工厂--新建具体工厂;根据抽象业务新建--具体业务
策略模式:
- 封装类:有策略的引用,处理策略;调用放实现封装类传入相关策略即可
// Context持有Strategy的引⽤,并且提供了调⽤策略的⽅法,
2 public class Context {
3
4 private Strategy strategy;
5
6 /**
7 * 传进的是⼀个具体的策略实例
8 * @param strategy
9 */
10 public Context(Strategy strategy) {
11 this.strategy = strategy;
12 }
13
14 /**
15 * 调⽤策略
16 */
17 public void contextInterface() {
18 strategy.algorithmLogic();
19 }
20
21 }
- 抽象策略角色,定义一组策略算法;封装重复代码
- 具体策略角色处理逻辑业务
调用方需要知道具体策略;并且有许多if-else判断逻辑实例化具体策略;可以用反射处理,配置具体名称
单例模式:
- 懒汉
- 饿汉
- 双重检查dcl
public class Mgr06 { // 1.私有引用 private static volatile Mgr06 INSTANCE; //JIT // 2.私有构造方法 private Mgr06() { } // 3.对外提供获取实例方法 public static Mgr06 getInstance() { if (INSTANCE == null) { //双重检查 synchronized (Mgr06.class) { if(INSTANCE == null) { INSTANCE = new Mgr06(); } } } return INSTANCE; } }
-
反射可以破坏单例
-
volatile指令重排序;保证可见性与防止重排序
代理模式:
- 抽象角色:abstract class Subject
- 代理角色: extends Subject 业务方法 ;需要真实角色的引用同时需要做真实角色的事, 在方法前后做自己的事
1 /** 2 * 静态代理,对具体真实对象直接引⽤ 3 * 代理⻆⾊,代理⻆⾊需要有对真实⻆⾊的引⽤, 4 * 代理做真实⻆⾊想做的事情 5 */ 6 public class ProxySubject extends Subject { 7 8 private RealSubject realSubject = null; 9 10 /** 11 * 除了代理真实⻆⾊做该做的事情,代理⻆⾊也可以提供附加操作, 12 * 如:preRequest()和postRequest() 13 */ 14 @Override 15 public void request() { 16 preRequest(); //真实⻆⾊操作前的附加操作 17 18 if(realSubject == null){ 19 realSubject = new RealSubject(); 20 } 21 realSubject.request(); 22 23 postRequest(); //真实⻆⾊操作后的附加操作 24 } 25 26 /** 27 * 真实⻆⾊操作前的附加操作 28 */ 21 优点:可以做到在不修改⽬标对象的功能前提下,对⽬标功能扩展. 缺点:每⼀个代理类都必须实现⼀遍委托类(也就是realsubject)的接⼝,如果接⼝增加⽅法,则代理类 也必须跟着修改。其次,代理类每⼀个接⼝对象对应⼀个委托对象,如果委托对象⾮常多,则静态代理类 就⾮常臃肿,难以胜任。
- 真实角色:extends Subject 业务方法
动态代理:jdk
- 创建⼀个动态代理类,实现InvocationHandler接⼝,并重写该invoke⽅法;不需要具体的引用实现动态代理但是在调用的使用利用反射处理
1 public class DynamicProxy implements InvocationHandler { 2 private Object object; 3 public DynamicProxy(Object object) { 4 this.object = object; 5 } 6 7 @Override 8 public Object invoke(Object proxy, Method method, Object[] ar gs) throws Throwable { 9 Object result = method.invoke(object, args); 10 return result; 11 } 12 } 1 Subject realSubject = new RealSubject(); 2 DynamicProxy proxy = new DynamicProxy(realSubject); 3 ClassLoader classLoader = realSubject.getClass().getClassLoader(); 4 Subject subject = (Subject) Proxy.newProxyInstance(classLoader, ne w Class[]{Subject.class}, proxy); 5 subject.visit();
cjlb动态代理 字节码处理 ASM框架:
- 实现MethodInterceptor,转发到该类的intercept()
-
11 // 2. 然后在需要使⽤HelloConcrete的时候,通过CGLIB动态代理获取代理对象。 12 Enhancer enhancer = new Enhancer(); 13 enhancer.setSuperclass(HelloConcrete.class); 14 enhancer.setCallback(new MyMethodInterceptor()); 15 16 HelloConcrete hello = (HelloConcrete)enhancer.create(); 17 System.out.println(hello.sayHello("I love you!"));
目标对象实现了接口默认使用JDK,没有实现接口只能用CJLB