代理模式一

2022-09-30 08:57:47 浏览数 (1)

普通代理

就是要求外部场景只能使用代理类,不允许使用原来的类。

直接上代码。

代码语言:javascript复制
public interface ICustomer {
    public void buy(); 
}

public class Customer implements ICustomer {
    private Strin name;
    // 不允许直接用 Customer 对象,所以在构造里判断是否有传一个代理过来
    // 如果没有代理就报错
    public Customer(ICustomer proxy, String name) throws Exception {
        if (proxy == null) {
            throw new Exception("必须用代理");
        } else {
            this.name = name;
        }
    }
    public void buy() {
        print("太难买了,排队12个小时终于买到了");
    }
}

public class Scalper implements ICustomer {
    private Customer customer = null;
    public Scalper(String name) {
        // 要有同样的参数,去构建被代理者
        this.customer = new Customer(this, name);
    }
    
    public void buy() {
        before();
        // 代理在调用被代理对象的同名方法时,可以前后有些处理
        customer.buy();
        after();
    }
    
    private void befor() {
        print("先谈价格,是原价的两倍");
    }

    private void after() {
        print("排12个小时,无所谓,因为赚钱了");
    }
}

// 场景类
public class Client {
    private void test() {
        // 外面直接创建代理对象
        ICustomer customer = new Scalper("zs");
        // 然后调用代理对象的方法,不知道 Customer 的存在
        customer.buy();
    }
}

强制代理

普通代理是高层创建代理对象,代理对象内部创建被代理对象。

强制代理是高层创建被代理对象,它的内部创建被代理对象,这样高层找到这个被代理对象后再做其它事情。

两者都是静态代理。

代码语言:javascript复制
public interface ICustomer {
    public void buy(); 
}

public class Customer implements ICustomer {
    private String name;
    private ICustome proxy; // 内部维护一个代理对象
    
    public Customer(String name) {
        this.name = name;
    }

    // 对外暴露,让高层调用者找到它的代理类,
    // 只能使用这个代理类,外面创建的不行
    public ICustomer getProxy() {
        proxy = new Scalper(this);
        return proxy;
    }
    
    public void buy() { // 保证只有外部获取过代理对象才可以调用
        if (proxy == null) {
            print("无法直接调用")
        } else {
            print("太难买了,排队12个小时终于买到了");
        }
    }
}

public class Scalper implements ICustomer {
    private ICustomer customer;
    // 高层调用者直接创建对象,所以这里不是代理内部根据参数创建
    // 而是直接用高层创建的那个
    public Scalper(ICustomer customer) {
        this.customer = custom;
    }
    
    public void buy() {
        before();
        // 代理在调用被代理对象的同名方法时,可以前后有些处理
        customer.buy();
        after();
    }
    
    private void befor() {
        print("先谈价格,是原价的两倍");
    }

    private void after() {
        print("排12个小时,无所谓,因为赚钱了");
    }
}

// 场景类
public class Client {
    public void test() {
        // 外面直接创建代理对象
        ICustomer customer = new Customer("zs");
        customer.getProxy().buy();
    }
}

动态代理

JDK 原生功能,使用 InvocationHandler 接口。不需要自己手动写代理类,写个 Handler 把要代理的对象传进来就行。

代码语言:javascript复制
public class CustomerIH implements InvocationHandler {
    Class clazz; // 被代理类
    Object obj; // 被代理类的实例
    public CustomIH(Object obj) { // 要代理谁
        this.obj = obj; 
    }
    // 实现接口必须要写的方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在执行被代理对象的方法前后可以做拦截,做判断
        Object result = method.invoke(this.obj, args); 
        return result;
    }
}

public class Client {
    public void test() {
        ICustomer customer = new Customer("zs"); // 被代理类实例
        InvocationHandler handler = new CustomerIH(customer);
        ICustomer proxy = (ICustomer) Proxy.newProxyInstance(
            custom.getClass().getClassLoader(),
            custom.getClass().getInterfaces(), 
            handler); // 创建代理类
        proxy.buy();
    }
}

Proxy.newProxyInstance 参数既有 ClassLoader,又有 Class,它会在内部创建一个类实现接口,方法通过 handler 的 invoke 去具体的实现。

动态代理不像静态代理需要修改 Custome 本身的代码,而可以扩展功能,适合 AOP 编程,但真要实现 AOP,直接用 AspectJ 了。

0 人点赞