07_代理模式

【新闻】

美国一家基础设施公司的安全审计发现,该公司的一位顶尖程序员将自己的工作外包给中国沈阳的一家软件公司。
该公司为雇员提供了VPN允许他们在家里工作。内部的安全审计发现,公司明星程序员Bob的VPN登陆日志显示他固定的从中国沈阳访问公司主服务器,他们找来电信设备供应商Verizon帮助调查。调查排除了恶意程序或黑客入侵的可能性。Verizon调查人员发现,Bob雇用了沈阳的一家软件咨询公司去做他的日常编程工作,通过FedEx提供了他的双步认证令牌,将六位数薪水的五分之一支付给外包公司,自己则去上网冲浪,比如在Reddit上逛几小时,然后去吃饭,再上ebay血拼,更新Facebook 和LinkedIn,最后给经理发送每日工作邮件,上床睡觉。他的计划一直行之有效,在公司人力资源眼里他是最高效的程序员之一,被认为是C, C++、Perl、Java、Ruby, PHP和Python方面的专家。目前Bob已被解雇。

【代理模式】

 代理模式又称为委托模式,为其它对象提供一种代理以控制对这个对象的访问。

 代理模式中含有3个角色:

1.Subject抽象主题角色(例子中的IProgrammaer接口)

抽象主题角色(抽象类或接口),是一个普通的业务逻辑定义,无特殊要求。

2.RealSubject 具体主题角色(即中国程序员)

也叫作被代理角色,他才是冤大头,是业务逻辑的具体执行者。

3.Proxy代理主题角色(即美国程序员)

也叫作代理角色,负责对正式角色的应用。

【静态代理模式的例子】

package com.Higgin.StaticProxy;

/**
 * 程序员接口
 */
interface IProgrammer{
    public void analyRequest();   //分析项目需求
    public void writeDocument();  //写项目文档
    public void coding();         //写代码
    public void test();           //测试代码
    public void deploy();         //部署工程
}
/**
 * 真实完成工作的程序员类(文中的中国程序员)
 */
class RealProgrammer implements IProgrammer{
    @Override
    public void analyRequest() {
        System.out.println("分析项目需求...");
    }
    @Override
    public void writeDocument() {
        System.out.println("编写项目文档...");
    }
    @Override
    public void coding() {
        System.out.println("写项目代码...");
    }
    @Override
    public void test() {
        System.out.println("测试项目...");
    }
    @Override
    public void deploy() {
        System.out.println("部署项目...");
    }
}

/**
 * 代理程序员类(文中的美国程序员)
 */
class ProgrammerProxy implements IProgrammer{
    private IProgrammer programmer;
    //通过该构造方法传入 中国程序员类
    public ProgrammerProxy(IProgrammer programmer){
        this.programmer=programmer;
    }
    
    @Override
    public void analyRequest() {
        programmer.analyRequest();
    }
    @Override
    public void writeDocument() {
        programmer.writeDocument();
    }
    @Override
    public void coding() {
        programmer.coding();
    }
    @Override
    public void test() {
        programmer.test();
    }
    @Override
    public void deploy() {
        programmer.deploy();
    }
}

/**
 * 静态代理 客户端 
 */
public class TestStaticProxy {
    public static void main(String[] args) {
        IProgrammer realProgrammer=new RealProgrammer();       //美国程序员
        IProgrammer proxy=new ProgrammerProxy(realProgrammer); //代理程序员
        //代理程序员完成各项工作
        proxy.analyRequest();   
        proxy.writeDocument();
        proxy.coding();
        proxy.test();
        proxy.deploy();
    }
}

【运行结果】

【动态代理(重点!!!)】

动态代理类的字节码在程序运行时由JAVA反射机制动态生成。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为JAVA反射可以生成任意类型的动态代理类。java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

【动态代理 例子】

package com.Higgin.DynamicProxy;

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

/**
 * 程序员接口
 */
interface IProgrammer{
    public void analyRequest();   //分析项目需求
    public void writeDocument();  //写项目文档
    public void coding();         //写代码
    public void test();           //测试代码
    public void deploy();         //部署工程
}
/**
 * 被代理的角色
 * 真实完成工作的程序员类(文中的中国程序员)
 */
class RealProgrammer implements IProgrammer{
    @Override
    public void analyRequest() {
        System.out.println("分析项目需求...");
    }
    @Override
    public void writeDocument() {
        System.out.println("编写项目文档...");
    }
    @Override
    public void coding() {
        System.out.println("写项目代码...");
    }
    @Override
    public void test() {
        System.out.println("测试项目...");
    }
    @Override
    public void deploy() {
        System.out.println("部署项目...");
    }
}

/**
 * 代理程序员类(文中的美国程序员)
 */
class ProgrammerProxy implements InvocationHandler{
    private Object obj=null;
    public ProgrammerProxy(Object obj){
        this.obj=obj;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //调用目标对象的方法 之前 的准备工作
        System.out.println("==============开始干这个任务前,我先喝口水==============");
        //调用具体目标对象的方法
        Object result=method.invoke(this.obj, args);
        //调用目标对象的方法 之后 的后续工作
        System.out.println("----------------任务完成了,我去上个厕所----------------");
        return null;
    }
}
/**
 * 动态代理客户端
 */
public class TestDynamicProxy {
     public static void main(String[] args) {
            IProgrammer realProgrammer=new RealProgrammer();       //中国程序员
            InvocationHandler handler=new ProgrammerProxy(realProgrammer); 
            
            ClassLoader cl=realProgrammer.getClass().getClassLoader();
            
            IProgrammer proxy=(IProgrammer) Proxy.newProxyInstance(cl, new Class[]{IProgrammer.class}, handler);
            
            //代理程序员完成各项工作
            proxy.analyRequest();   
            proxy.writeDocument();
            proxy.coding();
            proxy.test();
            proxy.deploy();
        }
}

【运行结果】

 【注意】

要实现动态代理类的首要条件是:被代理类必须实现一个接口。

【JDK动态代理小结】

JDK动态代理中重点是:一个类和一个接口。

[ InvocationHandler接口 ]

public interface InvocationHandler{
    public Object invoke( Object proxy, Method method , Obejct[] args ) throws Throwable ;
}

proxy : 被代理的对象

method:要被调用的方法

args:方法调用时所需要的参数

InvocationHandler接口的子类代替静态代理中的代理类。

[ Proxy类 ]

Proxy是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成代理类,此类提供了如下的操作方法:

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

loader:类加载器

interfaces:得到全部的接口

h:InvocationHandler接口的子类的实例

原文地址:https://www.cnblogs.com/HigginCui/p/6208227.html