Java 设计模式 - 动态代理模式

4 篇文章 0 订阅
3 篇文章 0 订阅

代理模式的定义:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问

代理模式通常分为静态代理模式动态代理模式。

简单来理解代理模式,其实就是客户端不直接对一个对象进行操作,而是将这些操作放在一个代理类中,由代理类完成操作,客户端只负责与代理类的交互即可。这样做一是可以提高代码的安全性、而是能够降低耦合度。

代理模式通常由三个角色组成

  1. Subject:抽象主题角色:通常作为真实主题角色的抽象接口,视业务情况有所不同。
  2. Proxy:代理主题角色:代理真实主题角色,负责和客户端进行交互。功能的扩展主要也是通过代理主题角色来关联并实现。
  3. RealSubject:真实主题角色:具体的功能主题角色。

由于静态代理模式比较简单,在文末补充上,这里先讲下动态代理模式。

需求:

假设有一个文件操作系统,提供对文件的增删改查操作,现在要在不修改源代码的前提下(开闭原则),使用代理模式,实现扩展一个功能:将每次对文件的操作和操作的时间写入日志文件log.txt中

文件系统的各种操作无需具体实现,只是模拟即可。

 

动态代理模式的实现如下:

①文件的操作对象分为抽象接口和具体实现。分别在动态代理模式中充当抽象主题角色具体主题角色

抽象主题角色:AbsFileOption

public interface AbsFileOption {

    public void find(File file);//查找文件

    public void update(File file,String updateContent);//修改文件

    public void delete(File file);//删除文件

    public void add(File file);//添加文件
    
}

具体主题角色:FileOption,简单的模拟实现了增删查改

public class FileOption implements AbsFileOption {

    @Override
    public void find(File file) {
        if(file.getName().equals("文件a") || file.getName() == "文件a")
            System.out.println("找到文件:"+file.getName());
        else
            System.out.println("未找到该文件");
    }

    @Override
    public void update(File file, String updateContent) {
        if(file.getName().equals("文件a") || file.getName() == "文件a")
            System.out.println("修改文件:"+file.getName()+",修改内容:"+updateContent);
        else
            System.out.println("修改失败");
    }

    @Override
    public void delete(File file) {
        if(file.getName().equals("文件a") || file.getName() == "文件a")
            System.out.println("删除文件:"+file.getName());
        else
            System.out.println("未找到该文件");
    }

    @Override
    public void add(File file) {
        if(file.getName().equals("文件a") || file.getName() == "文件a")
            System.out.println("添加文件:"+file.getName());
        else
            System.out.println("未找到该文件");
    }
}

②实现需求,创建一个写入日志的需求功能类,作为扩展对象。再创建一个代理主题角色,来实现需求中的功能扩展。

扩展对象类:WriteLog

public class WriteLog {
    //当前时间
    private String nowTime;
    //日志文件路径
    //System.getProperty("user.dir")获取的是项目的绝对路径
    private String path = System.getProperty("user.dir")+"\\src\\main\\java\\demo\\log.txt";
    //IO缓冲输出流
    private BufferedOutputStream bos;
    //将日志写入log.txt
    public void writeLog(String writeContent){
        nowTime = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date());
        try{
            File file = new File(path);
            if(!file.exists()){
                file.createNewFile();
            }
            bos = new BufferedOutputStream(new FileOutputStream(file,true));
            bos.write((nowTime+"\t"+writeContent+"\n-----------------------------\n").getBytes());
            bos.flush();
            bos.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

代理主题角色:FileLogProxy,需要实现InvocationHandler 接口(划重点

public class FileLogProxy implements InvocationHandler {
    //要代理的具体主题对象
    private Object target;

    //要扩展的具体主题对象
    private WriteLog writeLog = new WriteLog();;

    public FileLogProxy(Object object){
        this.target = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        beforeRequest(method.getName());//获取当前执行方法的方法名
        Object result = method.invoke(target,args);//转发调用
        afterRequest();
        return result;
    }

    //调用动态代理前的事件,将调用的方法名写入日志中
    public void beforeRequest(String methodName){
        System.out.println("写入日志中...");
        writeLog.writeLog("动态代理:调用方法"+methodName);

    }

    //调用动态代理后的事件
    public void afterRequest(){
        System.out.println("写入完毕");
    }
}

③创建一个客户端类来测试代理模式

客户端类:Client(划重点

public class Client {
    public static void main(String[] args) {
        InvocationHandler IHandler;

        AbsFileOption absFO = new FileOption();//获取文件操作的真实主题对象
        IHandler = new FileLogProxy(absFO);//将文件操作的真实主题对象传递给动态代理的构造方法
        ClassLoader classLoader = AbsFileOption.class.getClassLoader();//获取抽象主题的类加载器对象
        Class[] classes = new Class[]{AbsFileOption.class};//要代理的所有类对象集合

        //创建动态代理对象,用于代理AbsFileOption类型的真实主题对象
        AbsFileOption proxy = (AbsFileOption) Proxy.newProxyInstance(classLoader,classes,IHandler);

        //调用动态代理对象的业务方法
        proxy.find(new File("文件a"));

        proxy.update(new File("文件a"),"测试修改");

        proxy.delete(new File("文件a"));

        proxy.add(new File("文件a"));
    }
}

 打印台输出如下图

然后可以打开log.txt日志文件查看写入的内容

 

到这里,就成功通过动态代理实现对一个类的扩展。其实理解了代理模式的思想,在再理解动态代理并不难,关键在于要理解Proxy类和InvocationHandler接口的使用方法。

 

 

静态代理模式的实现如下:

如果上面的动态代理能够搞懂,相信静态代理只会觉得更加简单。只需要修改下上面的代理主题角色类FileLogProxy客户端测试类Client即可

FileLogProxy类如下:

public class FileLogProxy {
    //维持对文件操作真实主题的引用
    private AbsFileOption afo = new FileOption();

    //扩展功能的真实主题
    private WriteLog writeLog = new WriteLog();

    public void find(File file){
        afo.find(file);//不做修改,仍然使用原有的
        writeLog.writeLog("静态代理:调用方法find");//写入日志文件中
    }

    public void update(File file,String updateContent){
        afo.update(file,updateContent);
        writeLog.writeLog("静态代理:调用方法update");
    }

    public void delete(File file){
        afo.delete(file);
        writeLog.writeLog("静态代理:调用方法delete");
    }

    public void add(File file){
        afo.add(file);
        writeLog.writeLog("静态代理:调用方法add");
    }

}

Client类如下:

public class Client {
    public static void main(String[] args) {
        FileLogProxy fileLogProxy = new FileLogProxy();
        fileLogProxy.find(new File("静态文件a"));
        fileLogProxy.update(new File("静态文件a"),"测试修改");
        fileLogProxy.delete(new File("静态文件a"));
        fileLogProxy.add(new File("静态文件a"));
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值