模式的秘密-代理模式-静态代理

Posted 美好的明天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模式的秘密-代理模式-静态代理相关的知识,希望对你有一定的参考价值。

代理模式:

为其他对象提供一种代理以控制对这个对象的访问,代理对象起到了中介作用,可以去掉功能服务或者额外的服务。

 

以火车站买票为例子:

火车票代售处是火车站的代理,代售处可能不止可以卖火车票,还可以卖飞机票,但是不支持火车票退票功能,因此代售处起到了中介作用,

可以去掉功能服务或者额外的服务。

 

常见代理模式:远程代理,虚拟代理,保护代理,智能引用代理。

 

智能引用代理

两种实现方式:静态代理,动态代理。

 

静态代理:代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类。

静态代理分继承方式和聚合方式两种实现

实例:

通过代理,实现汽车行驶的方法,同时记录汽车的行驶时间。

 

普通不使用设计模式实现方式

第一步:行驶接口:

package com.Proxy;

public interface Moveable {
    
    void move();

}

第二步:实现汽车类:汽车类中实现行驶方法,里面记录行驶时间。

package com.Proxy;

import java.util.Random;

public class Car implements Moveable {

    @Override
    public void move()
    {
        long starttime=System.currentTimeMillis();
        System.out.println("汽车开始形式....");
        //实现开车
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽车行驶中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        long endtime=System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒");
    }

}

第三步:测试:

package com.Proxy;

public class Client {

    /*
     * 测试类
     * */
    public static void main(String[] args) {

        Car car=new Car();
        car.move();
    }

}

运行结果:

汽车开始形式....
汽车行驶中....
汽车结束行驶...汽车形式时间:602毫秒

 

修改为静态代理:

第一种静态代理:以继承的方式代理:

Car类修改为只有行驶方式:

package com.Proxy;

import java.util.Random;

public class Car implements Moveable {

    @Override
    public void move()
    {

        //实现开车
        try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println("汽车行驶中....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

新建Car2类继承Car类,通过super.方法()方式调用父类的方法,实现静态代理。

同时在这个方法里面实现记录开车时间。

package com.Proxy;

public class Car2 extends Car {

    @Override
    public void move() {
        
        long starttime=System.currentTimeMillis();
        System.out.println("汽车开始形式....");
        super.move();
        long endtime=System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒");
    }
}

测试:

package com.Proxy;

public class Client {

    /*
     * 测试类
     * */
    public static void main(String[] args) {

        Moveable m=new Car2();
        m.move();
    }
}

效果:

汽车开始形式....
汽车行驶中....
汽车结束行驶...汽车形式时间:497毫秒

 

第二种静态代理:以聚合的方式实现代理:

聚合的方式其实就是在一个类中调用另一个类的对象,一般在构造方法里面把另一个类的对象传进来。

实现:

Car类和接口同上。

新建Car3继承接口,同时在构造方法里面把Car类对象传进来。

package com.Proxy;

/*
 * 以聚合方式代理:一个类中调用另一个类的对象
 * */

public class Car3 implements Moveable{

    private Car car;
    
    public Car3(Car car)
    {
        this.car=car;
    }
    
    @Override
    public void move()
    {
        long starttime=System.currentTimeMillis();
        System.out.println("汽车开始形式....");
        car.move();
        long endtime=System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒");
    }
}

测试:

package com.Proxy;

public class Client {

    /*
     * 测试类
     * */
    public static void main(String[] args) {
//        不使用代理方式
//        Car car=new Car();
//        car.move();
        
//        //以继承方式实现代理
//        Moveable m=new Car2();
//        m.move();
        
        //以聚合方式实现代理
        Car car=new Car();
        Moveable m2=new Car3(car);
        m2.move();   
    }
}

效果:

汽车开始形式....
汽车行驶中....
汽车结束行驶...汽车形式时间:200毫秒

 

继承方式和聚合方式两种比较:

如果此时代理类除了要实现汽车行驶方法,还可能需要实现其他功能的代理,比如权限管理,日志处理。

 

1,对于继承方式的代理来说:

如果我想先记录汽车行驶时间,在记录日志,需要新建一个代理类。

假如此时我又想先记录日志,再记录汽车行驶时间,此时又得新建一个代理类。

所以使用继承方式不合适。

 

2,使用聚合方式就没这个问题,代码验证:

这里要实现两种方式:即先记录时间,再记录日志;和先记录日志,再记录时间。

 

实现的方式就是,各个功能分别建立一个代理类,并且代理类的构造方法不仅能够传递被代理类(Car),也能能够把其他的代理类传递进来,

以此实现上述的两种不同的实现方式

代码:

新建一个时间记录代理类:

为了可以让构造方法里面的参数既可以是被代理的Car类,也可以是代理类。

package com.Proxy;

//时间代理
public class CarTimeProxy implements Moveable{

    private Moveable m;
    
    public CarTimeProxy(Moveable m)
    {
        this.m=m;
    }
    
    @Override
    public void move()
    {
        long starttime=System.currentTimeMillis();
        System.out.println("汽车开始形式....");
        m.move();
        long endtime=System.currentTimeMillis();
        System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒");
    }
}

新建一个日志记录代理类:

package com.Proxy;

//日志代理
public class CarLogProxy implements Moveable{

    private Moveable m;
    
    public CarLogProxy(Moveable m)
    {
        this.m=m;
    }
    
    @Override
    public void move()
    {
        System.out.println("日志开始....");
        m.move();
        System.out.println("日志结束....");
    }
}

新建测试类:测试类分别通过两个代理类顺序不同,把相关代理类传递给另一个代理类调用:

package com.Proxy;

//聚合的代理模式,各个代理类直接可以互相传递,组合,
public class Clien2 {

    public static void main(String[] args) {

        Car car=new Car();
//        //先记录日志,再记录时间
//        CarTimeProxy ctp=new CarTimeProxy(car);
//        CarLogProxy clp=new CarLogProxy(ctp);//把时间代理传进去,这时候日志代理类代理了时间代理类
//        clp.move();

        //先记录日志,再记录日志,只需要调整一下代理类的顺序
        CarLogProxy clp2=new CarLogProxy(car);
        CarTimeProxy ctp2=new CarTimeProxy(clp2);//把时间代理传进去,这时候日志代理类代理了时间代理类
        ctp2.move();
        
    }
}

 

以上是关于模式的秘密-代理模式-静态代理的主要内容,如果未能解决你的问题,请参考以下文章

代理模式(静态代理动态代理)代码实战(详细)

代理模式(静态代理)

代理模式之静态代理实现代码

设计模式代理模式 ( 静态代理 )

模式的秘密-适配器模式和代理模式的区别

Spring之代理模式