java 设计模式之代理模式(七)

不要随意发脾气,人生在世,一个人不可能和所有认识的人都成为朋友。真正的朋友是强求不了的,老天也没规定谁必须和谁成为朋友,凡事都是要随缘的,生活中什么事都可以勉强,惟有“情”勉强不得,友情也是一样的道理。

设计模式学习,近期我会把23中设计模式都写成博客,敬请期待~
—2021/1/9

定义

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

百度百科

角色分类

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用

分析

假设我要去租房子,我肯定是先去找中介看房子,然后选取合适的房子租;

房子那里来的?那肯定是房东的吧

在这里房东就是一个需要代理的人,代理的东西就是房子,吧房子代理给中介,让中介帮忙出租给我们.

好处:

  • 房东没有任何改变,只是吧房子代理给了中介,中介得到房子之后向我们出租,并收取中介费等等.

UML类图(1.1):


分析:

  • HouseMaster 真实角色这里指房东
  • IHouse 抽象角色这里指房子
  • HouseProxy 代理角色这里指中介

静态代理实现:

IHouse(房子):

public interface IHouse {
    
    
    void showHouse();
}

HouseMaster(房东):

public class HouseMaster implements IHouse {
    
    

    @Override
    public void showHouse() {
    
    
        Log.i("代理模式:", "我是房东,我要出租房");
    }
}

HouseProxy(中介):

public class HouseProxy {
    
    

    IHouse house;
    //吧房子交给中介 (吧IHouse 接口组合到 HouseProxy 上)
    public HouseProxy( IHouse house) {
    
    
        this.house = house;
    }

    public void showHouse(){
    
    
        house.showHouse();//房东的房子
    }

}

使用代码:

//创建代理类 传入需要代理的类
HouseProxy houseProxy = new HouseProxy(new HouseMaster());

houseProxy.showHouse();

Log图(2.1):


可能大家对代理模式还是有所迷,我在详细解释一下

现在咋们只是通过HouseProxy(中介)来看房东A的房子,他还可以做其他操作,比如说,我们可以让他带着我们去看看其他的房子,我们还可以给中介小费:

HouseProxy(中介)类:

public class HouseProxy {
    
    

    IHouse house;
    public HouseProxy( IHouse house) {
    
    
        this.house = house;
    }

    public void showHouse(){
    
    
        money();//收取消费
        house.showHouse();//房东的房子
        seeHouse();//带用户看房
    }
    public void money(){
    
    
        Log.i("代理模式:","我是中介,我要收取消费");
    }
    public void seeHouse(){
    
    
        Log.i("代理模式:","我是中介,我带用户看房");
    }
}

Log图(2.2):


房东并没有发生变化,变化的只是中介
比如说在项目中,一个类用到了很多地方现在让这个这个类前面输出一句话,
咋们是不是就可以不在改变原有代码的基础上来达到这句话的显示呢?

静态代理模式总结:

优点:

  • 没有改变原有的代码,满足开闭原则(对修改关闭)
  • 公共代码交给代理类,实现了业务的分工
  • 不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。

缺点:

  • 一个类就需要创建一个代理类,代码量会翻倍,开发效率会降低

动态代理模式

动态代理指:代理类可以随着被代理的变化而变化,

简单的说就是我想A被代理,就A代理,想让B代理就被B代理,不用创建很多个代理类

角色:

  • InvocationHandler 调用处理程序
  • Proxy 代理

InvocationHandler是什么?

JDK1.8CHW图(3.1):


JDK1.8CHW下载 提取码:lfoz

InvocationHandler是由代理实例的调用处理程序实现的接口


InvocationHandler是一个接口,需要重写
invoke(Object proxy, Method method, Object[] args)方法

invoke方法解释:

  • 参数一(Object proxy):调用该方法的代理实例
  • 参数二(Method method):方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。 (这里听不懂没关系)
  • 参数三(Object[] args):包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。

这是jdk里面的解释:这里的方法解释看不明白没关系.

JDK1.8CHW图(3.2):

Proxy是什么?

JDK1.8CHW图(3.3):


Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。 (官方话)

我的理解:Proxy就是为了获取代理的实例

这么多字大家肯定不想看,简单的说就是:Proxy配合InvocationHandler使用完成代理类的自动生成

如果获取被代理的实例:

Proxy.newProxyInstance(
		ClassLoader loader,
        Class<?>[] interfaces,
        InvocationHandler h);

Proxy.newProxyInstance参数分析:

  • 参数一: 加载类所在位置
  • 参数二: 代理的接口
  • 参数三: 表示本身:InvocationHandler

代码实现:

ProxyInvocationHandler类:

public class ProxyInvocationHandler implements InvocationHandler {
    
    

    Object object;

    //参数一:object 具体接口的实现类
    public ProxyInvocationHandler(Object object) {
    
    
        this.object = object;
    }

    //生成代理类  返回的是被代理的接口 (返回的是object接口)
    public Object getProxy(){
    
    
        /**
         * this.getClass().getClassLoader() 加载类所在位置
         * object.getClass().getInterfaces() 代理的接口
         * this  表示本身:InvocationHandler
         */
       return Proxy.newProxyInstance(
			       this.getClass().getClassLoader(),
			       object.getClass().getInterfaces(),
			       this
	     	 );
    }

    /**
     * @param proxy 调用该方法的代理实例
     * @param method  所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
     * @param args 包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。
     *             原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
     * @return
     * @throws Throwable
     */
    @Override  //处理代理实例,返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        Object invoke = method.invoke(object, args);
        return  invoke;
    }
}

使用:

//需要代理 真实角色
HouseMaster houseMaster = new HouseMaster();

//代理类生成器  传入需要代理的类
ProxyInvocationHandler pit =
			 new ProxyInvocationHandler(houseMaster);

//生成代理类 (必须返回接口)
IHouse proxy = (IHouse) pit.getProxy();

//输出租房子
proxy.showHouse();

Log图(2.3):


HouseMaster(代理类)通过ProxyInvocationHandler(调用处理程序)类的反射机制自动生成了对应的IHouse(接口)

注意:


利用InvocationHandler的反射机制,获取当前调用的方法:

public class ProxyInvocationHandler implements InvocationHandler {
    
    

	.....
	
    @Override  //处理代理实例,返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        msg(method.getName());
        Object invoke = method.invoke(object, args);
        return  invoke;
    }

    public void msg(String msg){
    
    
        Log.i("代理模式","代理了"+ msg +"方法");
    }
}

流程图(4.1):


这里就是获取的showHouse()方法名

Log图(2.4):

现在这个ProxyInvocationHandler就是一个公共的代理类,传递进去一个需要代理的类,然后通过getProxy()就可以返回一个代理类的对象,(前提是传递进去的代理类要实现返回的代理类哦)

优点:

  • 没有改变原有的代码,满足开闭原则(对修改关闭)
  • 公共代码交给代理类,实现了业务的分工
  • 动态代理代理的是一个接口,一般是对应的一个业务
  • 一个动态代理可以代理多个接口,只要是实现同一个接口即可,相对于静态代理每一个被代理类都需要创建一个代理类来说,更加灵活

如果实在看不懂本篇的话会用也可以,因为这动态代码比较固定!

只要知道每个类扮演对应的角色会用就可以.

  • ProxyInvocationHandler调用处理程序 (用来自动生成代理类)

  • HouseMaster 真实角色(需要被代理的(本篇指房东出租房子))

  • IHouse 抽象角色(这里指房子)

  • pit.getProxy() 返回抽象角色(这里指返回房子)

  • proxy.showHouse(); 具体实现(指租房子)

完整项目

去设计模式/设计原则主页

原创不易,您的点赞就是对我最大的支持,点个赞支持一下哦~

猜你喜欢

转载自blog.csdn.net/weixin_44819566/article/details/112390541