设计模式讲解与代码实践(十三)——代理

本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!

1 目的

代理(Proxy)模式对被代理的对象的创建和访问进行控制。具体来说,代理模式有如下几个使用场景。

  1. 远程代理。为跨地址空间的远程访问提供包装转发;
  2. 虚代理。利用缓存减少对象的实例化;
  3. 保护代理。通过权限检查,过滤无操作权限的访问请求;
  4. 智能引用。实现对对象的读写锁及自动回收。

2 基本形态

代理的基本形态如类图2-1所示。
图2-1  代理类图
图2-1 代理类图

代理模式各对象间的调用关系如对象图2-2所示。
图2-2  代理对象图
图2-2 代理对象图

3 参与者

结合图2-1,下面介绍各类在代理设计模式中扮演的角色。
3.1 Subject
Subject是主体。它是代理类与被代理类同时需要实现的接口,以便在使用被代理类的地方用代理类做替换。
3.2 RealSubject
RealSubject是真正的主体类,即被代理的类。它实现了Subject接口。
3.3 Proxy
Proxy是代理类,实现了Subject接口。Proxy在适当的时机实例化RealSubject类,并调用其对应的方法。
3.4 Client
Client是客户类,是代理模式的使用者。Client用Proxy对象实例化Subject接口,通过Proxy间接调用RealSubject的方法。

4 代码实践

下面我们用一个业务场景实例来进一步讲解代理的使用。
4.1 场景介绍
某用户管理模块通过关系数据库存储用户信息。为了提高访问效率,用户管理模块在数据库基础上增加了一层缓存层。
以下各节将介绍该场景各类的具体实现及其在代理设计模式中所对应的参与者角色。
4.2 IUserDao
IUserDao是用户数据访问对象接口,声明了用户信息的数据库操作,即增删改查操作。对应于代理模式的参与者,IUserDao是主体Subject。下面的代码给出了IUserDao的声明。

package demo.designpattern.proxy;

/**
 * 用户数据访问对象接口
 * Created by LiMingzi on 2017/7/27.
 */
public interface IUserDao {
    /**
     * 获取用户信息
     * @param id 用户id
     * @return 用户信息json格式字符串,key为“id”的值为用户id,key为“name”的值为用户名
     */
    String getUserInfo(String id);

    /**
     * 更新用户信息
     * @param id 用户id
     *@param name 用户名
     */
    void updateUserInfo(String id,String name);

    /**
     * 删除用户
     * @param id 用户id
     */
    void delUser(String id);

    /**
     * 插入用户信息
     * @param id 用户id
     * @param name 用户名
     */
    void insertUserInfo(String id,String name);
}

4.3 UserDao
UserDao是用户数据访问类,实现了IUserDao接口。UserDao实现了对用户表的增删改查操作。对应于代理模式的参与者,UserDao是实际主体类RealSubject。下面的代码给出了UserDao的声明。

package demo.designpattern.proxy;

import java.util.HashMap;
import java.util.Map;

/**
 * 用户数据访问对象
 * Created by LiMingzi on 2017/7/27.
 */
public class UserDao implements IUserDao{
    /**
     * 用户字典,demo,代替数据库
     */
    private static Map<String,String> userMap = new HashMap<>();
    /**
     * 获取用户信息
     *
     * @param id 用户id
     * @return 用户信息json格式字符串,key为“id”的值为用户id,key为“name”的值为用户名
     */
    @Override
    public String getUserInfo(String id) {
        // 访问数据库
        System.out.println("访问数据库:select user_id,user_name from t_user where user_id = '"+id+"'");
        // 用户名
        String name =userMap.get(id);
        // 用户信息json
        String userInfoJson = "{'id':'"+id+"',name':'"+name+"'}";
        return userInfoJson;
    }

    /**
     * 更新用户信息
     *
     * @param id   用户id
     * @param name 用户名
     */
    @Override
    public void updateUserInfo(String id, String name) {
        // 访问数据库
        System.out.println("访问数据库:update t_user set user_name = '"+name+"' where user_id = '"+id+"'");
        userMap.put(id,name);
    }

    /**
     * 删除用户
     *
     * @param id 用户id
     */
    @Override
    public void delUser(String id) {
        // 访问数据库
        System.out.println("访问数据库:delete from t_user where user_id = '"+id+"'");
        userMap.remove(id);
    }

    /**
     * 插入用户信息
     *
     * @param id   用户id
     * @param name 用户名
     */
    @Override
    public void insertUserInfo(String id, String name) {
        // 访问数据库
        System.out.println("访问数据库:insert into t_user(user_id,user_name) values('"+id+"','"+name+"')");
        userMap.put(id,name);
    }
}

上述代码中,14行,静态成员变量userMap用于演示,替代数据库表存储用户数据。
4.4 UserDaoProxy
UserDaoProxy是用户数据库访问代理类,实现了IUserDao接口。对应于代理模式的参与者,UserDaoProxy是代理Proxy。下面的代码给出了UserDaoProxy的声明。

package demo.designpattern.proxy;

import java.util.HashMap;
import java.util.Map;

/**
 * 用户数据库访问对象代理
 * Created by LiMingzi on 2017/7/27.
 */
public class UserDaoProxy implements IUserDao{
    /**
     * 用户字典缓存demo,key为用户id,value为用户信息
     */
    private static Map<String,String> userMap= new HashMap<String,String>();
    /**
     * 获取用户信息
     *
     * @param id 用户id
     * @return 用户信息json格式字符串,key为“id”的值为用户id,key为“name”的值为用户名
     */
    @Override
    public String getUserInfo(String id) {
        // 用户信息json
        String userInfoJson;
        if(userMap.containsKey(id)){
            // 访问数据库
            System.out.println("访问缓存,查询id为'"+id+"'的用户信息");
            userInfoJson = userMap.get(id);
        }else{
            // 用户数据访问对象
            UserDao userDao = new UserDao();
            userInfoJson = userDao.getUserInfo(id);
            userMap.put(id,userInfoJson);
        }
        return userInfoJson;
    }

    /**
     * 更新用户信息
     *
     * @param id   用户id
     * @param name 用户名
     */
    @Override
    public void updateUserInfo(String id, String name) {
        if(userMap.containsKey(id)){
            userMap.remove(id);
            // 访问数据库
            System.out.println("访问缓存,移除id为'"+id+"'的用户信息");
        }
        // 用户数据访问对象
        UserDao userDao = new UserDao();
        userDao.updateUserInfo(id,name);
    }

    /**
     * 删除用户
     *
     * @param id 用户id
     */
    @Override
    public void delUser(String id) {
        if(userMap.containsKey(id)){
            userMap.remove(id);
            // 访问数据库
            System.out.println("访问缓存,移除id为'"+id+"'的用户信息");
        }
        // 用户数据访问对象
        UserDao userDao = new UserDao();
        userDao.delUser(id);
    }

    /**
     * 插入用户信息
     *
     * @param id   用户id
     * @param name 用户名
     */
    @Override
    public void insertUserInfo(String id, String name) {
        // 用户数据访问对象
        UserDao userDao = new UserDao();
        userDao.insertUserInfo(id,name);
    }
}

上述代码中,14行,静态成员变量userMap用于演示,替代业务场景中的缓存。22行,获取用户信息方法getUserInfo,只有用户信息不在缓存中才实例化被代理对象从数据库查询用户信息并写入缓存,否则直接从缓存返回用户信息。45行,更新用户信息方法updateUserInfo,在调用被代理对象的更新用户信息方法更新数据库表记录的同时还要清除缓存中的对应记录。62行,删除用户方法delUser,在调用被代理对象的删除用户信息方法删除数据库表记录的同时还要清除缓存中的对应记录。80行,插入用户信息方法insertUserInfo,直接调用被代理对象的插入用户方法。
4.5 UserMgmt
UserMgmt是用户管理类,通过用代理类UserDaoProxy对象实例化主体IUserDao接口实现对用户的操作。对应于代理模式的参与者,UserMgmt是客户Client。下面的代码给出了UserMgmt的声明。

package demo.designpattern.proxy;

/**
 * 用户管理类
 * Created by LiMingzi on 2017/7/27.
 */
public class UserMgmt {
    /**
     * 获取用户信息
     * @param id 用户id
     */
    public void getUser(String id){
        System.out.println("获取用户");
        // 用户数据库访问对象代理
        IUserDao userDao = new UserDaoProxy();
        System.out.println(userDao.getUserInfo(id));
    }

    /**
     * 更新用户信息
     * @param id 用户id
     *@param name 用户名
     */
    public void updateUser(String id,String name){
        System.out.println("更新用户");
        // 用户数据库访问对象代理
        IUserDao userDao = new UserDaoProxy();
        userDao.updateUserInfo(id,name);
    }

    /**
     * 删除用户
     * @param id 用户id
     */
    public  void delUser(String id){
        System.out.println("删除用户");
        // 用户数据库访问对象代理
        IUserDao userDao = new UserDaoProxy();
        userDao.delUser(id);
    }

    /**
     * 插入用户信息
     * @param id 用户id
     * @param name 用户名
     */
    public void insertUser(String id,String name){
        System.out.println("插入用户");
        // 用户数据库访问对象代理
        IUserDao userDao = new UserDaoProxy();
        userDao.insertUserInfo(id,name);
    }
}

4.6 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。从测试代码的输出可以很容易看到数据库和缓存的访问情况。

  /**
     * 代理测试
     */
    public static void proxyTest(){
        // 用户管理类
        UserMgmt userMgmt = new UserMgmt();
        userMgmt.insertUser("001","张三");
        System.out.println("-------------------------------------------");
        userMgmt.getUser("001");
        System.out.println("-------------------------------------------");
        userMgmt.getUser("001");
        System.out.println("-------------------------------------------");
        userMgmt.updateUser("001","张三(小)");
        System.out.println("-------------------------------------------");
        userMgmt.getUser("001");
        System.out.println("-------------------------------------------");
        userMgmt.delUser("001");
    }

编译运行后,得到如下测试结果:
插入用户
访问数据库:insert into t_user(user_id,user_name) values(‘001’,’张三’)

——————————————–

获取用户
访问数据库:select user_id,user_name from t_user where user_id = ‘001’
{‘id’:’001’,name’:’张三’}

——————————————–

获取用户
访问缓存,查询id为’001’的用户信息
{‘id’:’001’,name’:’张三’}

——————————————–

更新用户
访问缓存,移除id为’001’的用户信息
访问数据库:update t_user set user_name = ‘张三(小)’ where user_id = ‘001’

——————————————–

获取用户
访问数据库:select user_id,user_name from t_user where user_id = ‘001’
{‘id’:’001’,name’:’张三(小)’}

——————————————–

删除用户
访问缓存,移除id为’001’的用户信息
访问数据库:delete from t_user where user_id = ‘001’

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值