Java设计模式之代理模式

设计模式之代理模式

  代理模式,给某一个对象提供一个代理,并且由代理对象控制对原对象的引用。

代理模式结构图

  代理模式包含Subject(抽象主题角色),Proxy(代理主题角色)和RealSubject(真实主题角色)。
在这里插入图片描述

静态代理模式示例

  假设有一名毕业生,想要找工作,然后通过51job或者拉勾网进行找工作,投递简历,其实51job和拉勾网相当于个中介,替不同的企业代理,为企业收集了广大招聘者的简历,在这里企业就是就是Subject,想要招人,吸引招聘者投简历,而51job或者拉勾网发布企业的招聘信息,并且会为企业进行招聘推荐和宣传以及招聘后续的求职者的信息反馈。下面是Subject(抽象主题角色),公司的招聘接口,有一个发布职位的方法定义:

/*公司招聘接口,Subject(抽象主题角色)*/
public interface ICompanyRecruitment {

    /*发布招聘职位*/
    void publishRecruitment();
}

  RealSubject(真实主题角色),是具体的公司,实现Subject(抽象主题角色)的发布招聘职位的方法:

/*实际的主题角色(RealSubject),Facebook*/
public class FacebookCompanyRecruitment implements ICompanyRecruitment{
    @Override
    public void publishRecruitment() {
        System.out.println("Facebook发布:招聘高级算法工程师...");
    }
}

  Proxy(代理主题角色),是代理具体的公司,完成发布职位以及其他前置和后置的处理,代理对象可以在调用被代理对象时添加预处理和后置处理,代理类的实现如下:

/*招聘网站,代理公司发布招聘信息和一些前置和后置的处理*/
public class RecruitingWebsiteProxy  implements ICompanyRecruitment{

    /*实际的主题角色,也就是公司的发布招聘的实现*/
    ICompanyRecruitment companyRecruitment;

    public RecruitingWebsiteProxy() {
    }

    /*构造注入*/
    public RecruitingWebsiteProxy(ICompanyRecruitment companyRecruitment) {
        this.companyRecruitment = companyRecruitment;
    }

    /*setter注入,用来注入实际的主题角色对象,也可以使用构造注入*/
    public void setCompanyRecruitment(ICompanyRecruitment companyRecruitment){
        this.companyRecruitment = companyRecruitment;
    }

    @Override
    public void publishRecruitment() {
        System.out.println("前置:根据公司的不同,选择到不同的版块发布...");
        companyRecruitment.publishRecruitment();//发布公司的招聘信息
        System.out.println("后置:根据招聘岗位的类型,进行个性化的推荐指定用户群...");

    }
}

  测试类实现如下:

/*代理模式测试*/
public class Test {

    public static void main(String[] args) {
        /*1.实例化代理类的代理对象实例*/
        RecruitingWebsiteProxy recruitingWebsiteProxy = new RecruitingWebsiteProxy();
        /*2.设置实际的被代理对象*/
        ICompanyRecruitment facebookCompanyRecruitment = new FacebookCompanyRecruitment();
        recruitingWebsiteProxy.setCompanyRecruitment(facebookCompanyRecruitment);
        /*3.调用代理对象的实现*/
        recruitingWebsiteProxy.publishRecruitment();
    }
}

  测试程序执行结果:
在这里插入图片描述

动态代理模式示例

  如上面的静态代理模式,可以看出实际的主题角色是必须已经存在的,并且将它作为代理对象的内部成员属性。下面用动态代理实现上面的静态代理的实现,Subject(抽象主题角色),公司的招聘接口,有一个发布职位的方法定义:

下面是Subject(抽象主题角色),公司的招聘接口,有一个发布职位的方法定义:

/*公司招聘接口,Subject(抽象主题角色)*/
public interface ICompanyRecruitment {

    /*发布招聘职位*/
    void publishRecruitment();
}

  FacebookCompanyRecruitmentRealSubject(真实主题角色),真实角色A,是具体的公司,实现Subject(抽象主题角色)的发布招聘职位的方法:

/*实际的主题角色(RealSubject),Facebook*/
public class FacebookCompanyRecruitment implements ICompanyRecruitment{
    @Override
    public void publishRecruitment() {
        System.out.println("Facebook发布:招聘高级算法工程师...");
    }
}

  GoogleCompanyRecruitmentRealSubject(真实主题角色),真实角色B,是具体的公司,实现Subject(抽象主题角色)的发布招聘职位的方法:

/*实际的主题角色(RealSubject),Google*/
public class GoogleCompanyRecruitment implements ICompanyRecruitment {
    @Override
    public void publishRecruitment() {
        System.out.println("Google发布:招聘高级算法工程师...");
    }
}

  动态代理类:

public class DynamicRecruitingWebsiteProxy implements InvocationHandler {
    //被代理对象
    private Object obj;

    public DynamicRecruitingWebsiteProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置:根据公司的不同,选择到不同的版块发布...");
        method.invoke(obj,args);//发布公司的招聘信息
        System.out.println("后置:根据招聘岗位的类型,进行个性化的推荐指定用户群...");
        return null;
    }
}

  测试代码:

/*动态代理测试类*/
public class Client {

    /*DynamicRecruitingWebsiteProxy 只用了这个代理类实现了代理多个实际的被代理对象*/
    public static void main(String[] args) {
        InvocationHandler handler = null;
        ICompanyRecruitment companyRecruitment = null;

        /*1.Facebook发布招聘岗位*/
       System.out.println("=====================Fackbook==========================");
        handler = new DynamicRecruitingWebsiteProxy(new FacebookCompanyRecruitment());
        companyRecruitment = (ICompanyRecruitment) Proxy.newProxyInstance(ICompanyRecruitment.class.getClassLoader(),new Class[]{ICompanyRecruitment.class},handler);
        companyRecruitment.publishRecruitment();
        /*2.Google发布招聘岗位*/
        System.out.println("=====================Google==========================");
        handler = new DynamicRecruitingWebsiteProxy(new GoogleCompanyRecruitment());
        companyRecruitment = (ICompanyRecruitment) Proxy.newProxyInstance(ICompanyRecruitment.class.getClassLoader(),new Class[]{ICompanyRecruitment.class},handler);
        companyRecruitment.publishRecruitment();
    }
}

  测试结果:
在这里插入图片描述
  动态代理实现相关类为于java.lang.reflect包,主要涉及了两个类:

  • InvocationHandler接口。它是代理实例的调用处理程序实现的接口,改接口定义了如下方法:

     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    

    该方法中第一个参数proxy表示代理类,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。

  • Proxy类。该类即动态代理类,该类最常用的方法为:

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

    newProxyInstance()方法用于根据传入的接口类型interfaces返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类实现的接口列表(与真实主题类的接口列表一致),第三个参数h表示所指派的调用处理程序类。

什么场景下使用代理模式

  如果某个应用的调用端不想或者不能直接引用一个对象,此时可以采用代理模式。

代理模式优缺点

优点:能够协调调用者和被调用者,降低了系统的耦合度。
缺点:由于增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

静态代理和动态代理的区别

a.静态代理,代理类需要自己编写代码产生。
b.动态代理,代理类通过 Proxy.newInstance() 方法产生。
c.静态代理和动态代理的区别是在于是否需要开发者自己定义 Proxy 类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值