zoukankan      html  css  js  c++  java
  • 《设计模式五》代理、迭代器、访问者模式

    1.11 代理模式-Proxy(重要)

    1.11.1 聚合方式(静态代理)

    • 该代理需要和被代理对象实现相同的接口
    class CarProxy implements Movable {
        // 可改进为 Movable m;
        Car car;
        
        public CarProxy (Car car) {
            this.car= car;
        }
        
        @Override
        public void move() {
            long start = System.currentTimeMillis();
            car.move();
            long end = System.currentTimeMillis();
            System.out.println(end - start);
        }
    }
    
    interface Movable{
        void move();
    }
    
    

    该代理聚合了car,代理了car的move方法,自己添加了打点计时。其他所有工作都是car也就是被代理对象做的

    该聚合代理,也叫静态代理,可以改进代理实现Movable的各种,由于Car和代理对象都实现了Movable接口,改进为代理Movable的代理可以嵌套其他的代理,比如时间代理中聚合一个日志代理

    // 即可在Car上实现时间和日志的双重代理
    new CarLogProxy(new CarLogProxy(new Car());
    

    代理模式很像装饰模式,本质上都像多态的应用

    静态代理实现需要知道被代理的对象,被代理的方法,如何设计一个全能的动态代理?

    1.11.2 JDK动态代理(反射)

    public static void main(String[] args) {
        Car car = new Car();
        // feflecion 通过字节码分析类的属性和方法
        Movable m = (Movable)Proxy.newProxyInstance(Car.class.getClassLoader(), 
        new Class[]{Movable.class},
        new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method meyhod, Object[] args) throws Exception {
                System.out.println("method "+method.getName + "start ...");
                Object o = method.invoke(car , args);
                System.out.println("method " + method.getName() + " end!");
                return o;
            }
        });
        m.move();
    }
    

    代理的newProxyInstance参数解释:newProxyInstance(ClassLoad loader, Class<?>[] interfaces, InvocationHandler h)。
    第一个参数表示要new出来被代理对象的加载器,第二个参数表示你new出来的代理需要有哪些接口,第三个参数表示被代理对象的接口方法被调用,我们的处理策略

    • JDK的asm框架可以直接操作二进制码,无需改源码再重新编译类。动态代理和asm有很大关系。有了asm之后,Java可以被称为动态语言。反射只能找到运行时的类信息,改运行时的类,需要借助asm

    JDK动态代理的缺点,被代理的类必须是实现接口的方式

    1.12.3 cglib动态代理

    被代理对象无需实现接口,且调用简单

    • 引入maven依赖
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib<artifactId>
        <version>3.2.12</version>
    </dependency>
    
    • 流程:
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Car.class);
        enhancer.setCallback(new TimeMethodInterceptor());
        Car car= (Car)enhancer.create();
        car.move;
    }
    
    class TimeMethodInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {
            System.out.println("before");
            Object result = null;
            result = methodProxy.invokeSuper(o, objects);
            System.out.println("after");
            return result;
        }
    }
    
    

    cglib缺点,无法代理final的类,因为cglib实质代理的是被代理类的子类,但是asm可以代理final的被代理类。cglib底层也是用的asm

    1.11.4 Spring的AOP切面

    就是配置要对那些方法,代理,也就是切入(织入)
    Spring关于aop的xml配置切面:

    <aop:config>
        <aop:aspect id="time" ref="timeProxy">
            <aop:pointcut id="onmove" expression="com.darope.Car.onmove()">
            <aop:before method="before" pointcut-ref="onmove">
            <aop:after method="after" pointcut-ref="onmove">
        </aop:aspect>
    </aop:config>
    

    Spring关于aop的注解配置:

    <!—开启自动代理—>
    <aop:aspectj-autoproxy/>
    

    代理类上加切面注解:

    @Aspect
    public class TimeProxy {
        @Before("execution(com.darope.Car.move())")
        public viod before() {
            System.out.println("hello=====")
        }
        
        @After("execution(com.darope.Car.move())")
        public viod after() {
            System.out.println("hello=====")
        }
    }
    

    注意,业务上使用代理模式,基本上都是使用Spring的动态代理,也就是用Spring的AOP切面来实现代理功能,增加我们前置增强和后置增强

    1.12 迭代器模式-Iterator

    用在容器上,遍历的方法

    存储结构:物理上只有两种存储结构,数组,链表。其他都是逻辑存储

    迭代器模式,就是不同结构实现Iterator,包含next和hasNext,其他方法调用,就可以遍历该结构

    1.13 访问者模式-Visoitor(不重要)

    在结构不变的情况下,动态改变对于内部元素的动作。也就是说如果电脑城产品不停更新,例如加入蓝牙,键盘等产品,那么久不适合观察者模式

    电脑配件商店根据顾客不同,进行打折力度不同,通常就是if-else。

    解决的办法,是定义Visitor接口,里面包含visitCpu,visitMem,visitorBoard方法

    interface Vistor {
        void visitCpu(Cpu cpu);
        void visitMem(Mem mem);
        void visitBoard(Board board);
    }
    

    电脑配件类:

    public class Compute {
        ComputePart cpu = new Cpu();
        ComputePart memory = new Memory();
        ComputePart board = new Board();
        
        public void accept(Visitor v) {
            this.cpu.accpt(v);
            this.mem.accpt(v);
            this.board.accpt(v);
        }
    }
    

    来访的顾客,需要实现该接口,对应打折的不同实现,例如:

    class studentVistor implements Vistor {
        double price = 0.0;
    
        void visitCpu(Cpu cpu) {
            price += cpu.getPrice() * 0.6;
        }
        void visitMem(Mem mem) {
            price += mem.getPrice() * 0.8;
        }
        void visitBoard(Board board) {
            price += board.getPrice() * 0.7;
        }
    }
    
  • 相关阅读:
    北京燃气IC卡充值笔记
    随机分析、随机控制等科目在量化投资、计算金融方向有哪些应用?
    量化交易平台大全
    Doctor of Philosophy in Computational and Mathematical Engineering
    Institute for Computational and Mathematical Engineering
    Requirements for the Master of Science in Computational and Mathematical Engineering
    MSc in Mathematical and Computational Finance
    万字长文:详解多智能体强化学习的基础和应用
    数据处理思想和程序架构: 使用Mbedtls包中的SSL,和服务器进行网络加密通信
    31-STM32+W5500+AIR202/302基本控制篇-功能优化-W5500移植mbedtls库以SSL方式连接MQTT服务器(单向忽略认证)
  • 原文地址:https://www.cnblogs.com/darope/p/12734709.html
Copyright © 2011-2022 走看看