前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代理模式一

代理模式一

作者头像
三流编程
发布2022-09-30 08:57:47
1230
发布2022-09-30 08:57:47
举报

普通代理

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

直接上代码。

代码语言: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 了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-09-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 普通代理
  • 强制代理
  • 动态代理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档