设计模式之代理模式

一、代理模式的概念

当一个类无法直接使用另外一个类时,使用一个代理类来达到使用的目的。

这句话是什么意思呢,举一个生活中的例子,现在的人都喜欢去北上广深打工,打工难免要租房子,而租房子,是很难直接去找到房东去租的,一般都需要通过中介来达到中间沟通的作用,这也是为什么中介可以在中间赚差价的原因。
我们把类无法直接使用的类称为目标类,在这个例子中,房东就代表目标类,而中介就是代理类,租客必须通过中介才能联系到房东,这就是代理模式的思想

二、代理模式的作用

1.功能增强:在你原有的功能之上,增加额外的功能。新增加的功能,叫做功能增强。例如:房东给出的房租是2000/月,而中介告诉你房租是2500/月这就代表功能增强,哈哈
2.控制访问:代理类不让你访问目标,例如:中介为了赚钱,不会让你和房东直接沟通

三、代理模式的实现

代理模式有两种实现方式:
1.静态代理:
1)代理类是自己手工实现的,自己创建一个java类,表示代理类。
2)同时你要代理的目标类是确定的。
下面我们用静态代理来实现上述中的例子
首先创建接口,实现租房功能

package cn.geezer.service;

public interface RentRoom {
    /**
     * 创建接口租房子接口,和出租方法!
     *
     * @return 房子的租金/月
     */
    float rent();
}

创建目标类,也就是房东

package cn.geezer.target;

import cn.geezer.service.RentRoom;

public class HouseOwner implements RentRoom {
    /**
     * 房东实现租房接口,实现出租方法
     *
     * @return 房子的价格:2000/月
     */
    public float rent() {
        System.out.println("房东提供房租!");
        return 2000.0f;
    }
}

创建代理类,也就是中介

package cn.geezer.service;

import cn.geezer.target.HouseOwner;

public class HouseAgent implements RentRoom {
    private RentRoom owner;//代理房东
    public HouseAgent() {
        this.owner = new HouseOwner();
    }

    /**
     * @return 房子的价格 2500/月
     */
    public float rent() {
        float price = owner.rent();
        price = price + 500;//中介在其中赚差价(功能增强)
        System.out.println("中介在其中赚差价!");
        return price;
    }

}

创建租客类,租房子

package cn.geezer.main;

import cn.geezer.service.HouseAgent;

public class Tenant {
    // 租客
    public static void main(String[] args) {
        HouseAgent agent = new HouseAgent();
        float price = agent.rent();
        System.out.println("租房的价格为:" + price + "元/月");
    }
}

通过以上例子不难看出静态代理的优缺点
优点:实现简单,容易理解
缺点:当目标类和代理类太多的时候,存在以下缺点
1)目标类增加,代理类也需要随着增加
2)修改或增加方法,所有代理类需要修改
因为以上缺点,jdk提供了动态代理的方法来解决
在了解动态代理之前,需要先学习几个类
1)InvocationHandler接口(调用处理器):就一个方法invoke()
invoke():表示代理对象要执行的功能代码,你的代理类要完成的功能就写在invoke()方法中
代理类完成的功能:
1)调用目标类的方法,执行目标方法的功能
2)功能增强,在目标方法调用时,增加功能
方法原型:
public Object invoke(Object proxy, Method method, Object[] args)
参数:
Object proxy:jdk创建的代理对象,无需赋值
Method method:目标类中的方法,jdk提供method对象
Object[] args:目标类中方法的参数,jdk提供
2)Method类:表示方法的,确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,method.invoke();
3)Proxy类:核心对象,创建代理对象,之前创建对象都是new类的构造方法()
方法:静态方法newProxyInstance()
作用是:创建代理对象
方法原型:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)	

参数:
1.classLoader loader类加载器,负责向内存中加载对象,使用反射获取对象的ClassLoader类a,a.getClass().getClassLoader(),目标对象的类加载器

2.Class<?>[] interfaces:接口,目标对象实现的接口,也是反射获取的

3.InvocationHandler h 自己写的代理类要完成的功能
返回值就是代理对象

下面用动态代理的方式来实现租房子的例子
接口和房东代码和上面一样
创建InvocationHandler接口

package cn.geezer.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class HouseInvocationHandler implements InvocationHandler {
    RentRoom rentRoom;

    public HouseInvocationHandler(RentRoom rentRoom) {
        this.rentRoom = rentRoom;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	//利用反射来执行目标类方法
        Float price = (Float) method.invoke(rentRoom, args);
        System.out.println("中介在其中赚差价!");
        price = price + 500;
        return price;
    }
}

租客类

package cn.geezer.main;

import cn.geezer.service.HouseInvocationHandler;
import cn.geezer.service.RentRoom;
import cn.geezer.target.HouseOwner;

import java.lang.reflect.Proxy;

public class Tenant {
    public static void main(String[] args) {
        HouseOwner owner = new HouseOwner();
        HouseInvocationHandler handler = new HouseInvocationHandler(owner);
        RentRoom agent = (RentRoom) Proxy.newProxyInstance(owner.getClass().getClassLoader(), owner.getClass().getInterfaces(), handler);
        float price = agent.rent();
        System.out.println("租房的价格为:" + price + "元/月");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值