代理模式。

代理模式

代理模式 顾名思义就是为我们真正使用的对象寻找一个代理,我们通过调用代理对象的方法间接地调用真正使用的对象的方法。就像我们生活中去工厂打工,不直接去工厂,而去找中介、去旅游不直接去旅游目的地,而是去找旅行社一样。

代理模式的优点:
(1)代理模式能将代理对象与真实被调用目标对象分离。
(2)在一定程度上降低了系统的耦合性,扩展性好。
(3)可以起到保护目标对象的作用。
(4)可以增强目标对象的功能。
代理模式的缺点:
(1)代理模式会造成系统设计中类的数量增加。
(2)在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢。
(3)增加了系统的复杂度。

静态代理

静态代理的角色分工

  1. 代理类 和 实现类 公用的接口
  2. 实现类
  3. 代理类

如下,定义了查询数据库的接口UserDao,和UserDao的实现类UserDaoImp,以及代理类UserDaoProxy。我们同通过代理类UserDaoProxy给UserDaoImp的select方法增加一些之执行前后的处理。

public interface UserDao {
    void select(String id);
}

public class UserDaoImp implements UserDao{
    @Override
    public void select(String id) {
        System.out.println("已查询到id为"+id+"的用户信息");
    }
}

public class UserDaoProxy implements UserDao{
    private UserDao userDao;
	// 前置方法增强
    private void before(){
        System.out.println("正在执行查询数据前的数据库连接操作");
    }
	// 后置方法增强
    private void after(){
        System.out.println("正在执行关闭数据库连接操作");
    }

    public UserDaoProxy(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void select(String id) {
        before();
        this.userDao.select(id);
        after();
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        UserDaoProxy userDaoProxy = new UserDaoProxy(new UserDaoImp());
        userDaoProxy.select("110");
    }
}

动态代理

静态代理的方式需要我们手动地编写代理类的代码,如果是一两个还好,但如果有多个不同的类需要代理,静态方法就不太适合了,这时我们就可以用动态代理来实现。

动态代理类的角色分工

  1. 接口
  2. 实现类
  3. 生成代理对象的类

public interface UserDao {
    void queryUserById(String id);
    void queryUserByUsername(String username);
    void removeUser(String id);
}

public class UserDaoImp implements UserDao {

    @Override
    public void queryUserById(String id) {
        System.out.println("已查询到id为"+id+"的用户信息");
    }

    @Override
    public void queryUserByUsername(String username) {
        System.out.println("已查询到username为"+username+"的用户信息");

    }

    @Override
    public void removeUser(String id) {
        System.out.println("删除用户成功");
    }
}

生成代理对象的类

public class CommonProxy implements InvocationHandler {
    private Object target;      // 保存被代理的对象的引用
    
    public CommonProxy(Object target) {
        this.target = target;
    }

    public  Object newInstanse(){
        Class<?> clazz = target.getClass();
        Object o = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
        return o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        Object obj = null;
        // 只对query开头的方法代理
        if(name.startsWith("query")){
            before();       //前置增强
           obj = method.invoke(this.target, args);
            after();        //后置增强
        }else{  //      其他方法不代理,直接调用
            obj = method.invoke(this.target,args);
        }
        return obj;
    }

    private void before(){
        System.out.println("执行查询操作前的准备");
    }
    private void after(){
        System.out.println("执行查询操作后的准备");
        System.out.println();
    }
}

测试代码

public class Test {
    public static void main(String[] args) {
        UserDao userDao = (UserDao) new CommonProxy(new UserDaoImp()).newInstanse();
        userDao.queryUserById("110");
        userDao.queryUserByUsername("王五");
        userDao.removeUser("120");
    }
}

这样我们不仅可以代理UserDao的子类,也可以代理其他的类,只要被代理的目标类中含有query开头的方法,就能对该方法增强。

静态代理与动态代理的对比

(1)静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加,违背开闭原则。
(2)动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。
(3)若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无须修改代理类的代码。
(4)动态代理用到反射技术,速度较慢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值