Spring运用的设计模式

Spring的设计模式

设计模式

动态代理

JDK动态代理
  • Proxy:获得代理对象
    代理对象 extends Proxy implement 目标类接口
// 返回代理对象
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)// 通过执行对象调用目标对象的方法,增强的逻辑是写InvocationHandler的实例在invoke()
//loader:目标类的类加载器,代码生成后,编译,重新动态load.class到JVM;
//interfaces:目标类的所有接口,获得代理的方法;
//h:实现InvocationHandler接口类的实例,重写invoke,执行者
  • 原理流程
    1、生成源代码.java,与目标对象实现相同的接口
    2、将生成的源代码.java文件
    3、编译源代码,并且生成.Class文件
    4、将class文件中的内容,动态加载JVM中来
    5、返回被代理后的代理对象
    6、所有通过代理对象调用方法,实际就是执行者的invoke()

  • code

/**
 * 目标类接口
 *
 * @author xw
 * @date 2019/9/23 23:55
 */
public interface Person {

    void getName();
}

/**
 * 目标被代理类
 *
 * @author xw
 * @date 2019/9/23 23:56
 */
public class Guojiang implements Person {

    @Override
    public void getName() {
        System.out.println("姓名:锅酱~");
        System.out.println("锅酱,在找女朋友~");
    }
}

/**
 * 媒婆执行增强类
 *
 * @author xw
 * @date 2019/9/24 11:13
 */
public class MeiPo implements InvocationHandler {

    //目标对象引用
    private Person target;

    public Object getProxy(Person target) {
        this.target = target;
        Class clazz = target.getClass();
        /** 
         * 为了获得目标对象的信息
         * clazz.getClassLoader():目标对象的类加载器
         * clazz.getInterfaces():目标对象的接口数组
         * this:实现InvocationHandler接口实例
         */
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }


    /**
     * 所有代理对象执行接口方法都会被拦截,逻辑增强也是在此
     * 媒婆类就是执行者,JDK生成的代理对象,实际调用执行者来增强逻辑
     *
     * @param proxy  代理对象的引用
     * @param method 方法对象
     * @param args   方法参数
     * @return 方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 执行者调用目标对象的方法
        method.invoke(target, args);
        System.out.println("增强逻辑.....");
        return null;
    }
}
CGLib动态代理
  • MethodInterceptor 方法拦截接口

  • code

/**
 * 目标学生类
 *
 * @author xw
 * @date 2019/9/24 14:02
 */
public class Student {

    public void study() {
        System.out.println("学习~~~");
    }
}

/**
 * 执行类
 *
 * @author xw
 * @date 2019/9/24 14:02
 */
public class ProxyStudent implements MethodInterceptor {

    /**
     * 获得代理对象
     *
     * @param clazz 目标对象
     * @return
     */
    public Object getInstance(Class clazz) {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(clazz);
        //回调
        enhancer.setCallback(this);
        /**
         * 创建代理对象
         * 1.生成源代码
         * 2.编译class文件
         * 3.加载进JVM,并返回代理对象
         */
        return enhancer.create();
    }


    /**
     * 方法拦截,增强
     *
     * @param obj    目标对象引用
     * @param method 执行的方法对象
     * @param args   方法参数
     * @param proxy  代理对象引用
     * @return 方法的返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //调用父类的方法
        //这个obi的引用是由CGLib给我们new出来的
        //cglib new出来的对象,是被代理对象的子类(子父类关系)
        //00P,在new子类之前,实际上默认先调用了我们super()方法的,
        //new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用
        //子类重写了父类的所有的方法
        //当改变子类对象的某些属性,是可以间接的操作父类的属性的
        proxy.invokeSuper(obj, args);
        System.out.println("CGLib增强逻辑,请代练学习....");
        return null;
    }
}

总结

动态代理本质是字节码重组

  • JDK动态代理与CGLib动态代理区别
  1. JDK的动态代理是基于接口的,通过接口进行强制转换的生成以后的代理对象。[代理对象 extends Proxy implement 目标类接口]
  2. CGLib的动态代理基于继承子父类关系,通过生成一个被代理对象的子类,然后重写父类的方法,生成的对象,可以强制转换为被代理对象(也就是用自己写的类),子类引用赋值给父类。

工厂模式

隐藏复杂的逻辑处理过程,只关心执行结果。

简单工厂
  • 特点
    只需给定指定条件,工厂包含必要逻辑判断,依据条件实例化所需产品
    在用到简单工厂的情况下,可以考虑反射去除switch或if分钟的耦合
  • 缺点
    代码逻辑判断紊乱,维护困难耦合高,拓展不灵活
  • code
/**
 * @author xw
 * @date 2019/8/2 22:06
 * 计算器最顶层接口
 */
public interface Operation {
    
    public Double getResult(Double a, Double b);

}

/**
 * @author xw
 * @date 2019/8/2 22:23
 * 运算工厂类
 */
public class OperationFactory {
    /**
     * 简单工厂
     * @param str 运算符
     * @return  
     */
    public static Operation creatOper(String str) {
        Operation oper =null;
        switch (str) {
            case "+":
                oper = new AddOperation();
                return oper;
            case "-":
                oper = new SubOperartion();
                return oper;
            case "/":
                oper = new DivisionOperartion();
                return oper;
            default:
                return oper;
        }
    }
}
工厂方法
/**
 * 工厂方法
 *
 * @author xw
 * @date 2019/9/24 16:01
 */
public class BMWFactory {
    //通常是静态方法
    public Car getCar() {
        System.out.println("BMW工厂生产汽车");
        return new Car("BWM");
    }
}
抽象工厂
  • 抽象工厂包含所有产品的创建的抽象方法,由具体工厂去实现产品,由客户端决定使用哪个工厂。
/**
 * 抽象工厂
 *
 * @author xw
 * @date 2019/9/24 15:46
 */
public abstract class AbstractFactory {

    abstract Car getCar();

    public Car getCar(String name) {
        if ("BMW".equalsIgnoreCase(name)) {
            return new BMWFactory().getCar();
        } else if (name == null) {
            System.out.println("无工厂生产");
            return null;
        }
        return null;
    }
}

/**
 * 具体工厂实现
 *
 * @author xw
 * @date 2019/9/24 16:01
 */
public class BMWFactory extends AbstractFactory {

    public Car getCar() {
        System.out.println("BMW工厂生产汽车");
        return new Car("BWM");
    }
}

/**
 * 默认工厂
 *
 * @author xw
 * @date 2019/9/24 16:05
 */
public class DefaultFactory extends AbstractFactory {

    //默认工厂
    private BMWFactory factory = new BMWFactory();

    @Override
    Car getCar() {
        System.out.println("默认工厂创建对象");
        return factory.getCar();
    }
}

//客户端调用
 public static void main(String[] args) {
        DefaultFactory fatory = new DefaultFactory();
        //默认工厂生产
        fatory.getCar();
        System.out.println("**********");
        //指定工厂生产产品
        fatory.getCar("BMW");
    }

单例模式

  • 特点
    1、保证从系统启动到系统终止,全过程只会产生一个实例。
    2、当我们在应用中遇到功能性冲突(例如配置文件)的时候,需要使用单例模式。

  • JVM加载类的顺序

  1. 从上到下(声明前,使用后)
  2. 先属性(成员),后方法
  3. 先静态,后非静态
  4. 先父类,后子类
    父类的静态字段——>父类静态代码块——>子类静态字段——>子类静态代码块——>
    父类成员变量(非静态字段)——>父类非静态代码块——>父类构造器——>子类成员变量——>子类非静态代码块——>子类构造器
  • code
 //懒汉式(静态内部类)
 //即解决安全问题,又解决了性能问题
    public class Singleton4 {
        //1、先声明一个静态内部类
        //private 私有的保证别人不能修改
        //static 保证全局唯一
        private static class LazyHolder {
            //final为了防止内部误操作
            private static final Singleton4 INSTANCE = new Singleton4();

            //2、将默认构造方法私有化
            private Singleton4() {
            }

            //3、同样提供静态方法获取实例//final 确保别人不能覆盖
            public static final Singleton4 getInstance() {
                return LazyHolder.INSTANCE;
            }
        }
    }

委派模式

  • 特点
    1、类似于中介的功能(委托机制,受托人,委托人);
    2、持有被委托人的引用。
    3、不关系过程,只关心结果
  • 目的
    隐藏具体实现逻辑
    保证结果的多样性,对于外暴露只有一种方法
  • code
/**
 * 执行的事
 *
 * @author xw
 * @date 2019/9/24 16:59
 */
public interface IExector {

    void doSomething();
}

/**
 * 具体执行者
 *
 * @author xw
 * @date 2019/9/24 16:59
 */
public class ExectorA implements IExector {
    @Override
    public void doSomething() {
        System.out.println("开始干活...");
    }

    public static void main(String[] args) {
        DispatcherExctor dispatcherExctor = new DispatcherExctor(new ExectorA());
        //委托执行
        dispatcherExctor.doSomething();
    }
}

/**
 * 委托人
 *
 * @author xw
 * @date 2019/9/24 17:00
 */
public class DispatcherExctor implements IExector {

    //被委托人的引用
    private IExector exector;

    public DispatcherExctor(IExector exector) {
        this.exector = exector;
    }

    @Override
    public void doSomething() {
        System.out.println("指定委托他人干活...");
        exector.doSomething();
    }
}

public static void main(String[] args) {
        //受托人接任务
        DispatcherExctor dispatcherExctor = new DispatcherExctor(new ExectorA());
        //受托人委托执行人执行
        dispatcherExctor.doSomething();
    }
  • 委派模式和工厂模式的区别?
  1. 工厂模式是生产固定的产品,针对具体的结果(产品);
    委派模式针对的是具体的执行者,只需要满足执行标准(实现相同的接口)
  2. 工厂模式返回的一个实例对象,关心的是Bean;
    委派模式是具体执行方法,关心的是方法。
  3. 工厂模式可以看做固定的委派模式
  • 与代理模式的区别?

策略模式

1、最终执行结果是固定的。
2、执行过程和执行逻辑不一样。

原型模式

1、首先有一个原型。
2、数据内容相同,但对象实例不同(完全两个不同的内存地址)。

模板模式

  • 流程是固定的,不同实例有些不同
    完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;
    就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值