Head First设计模式(阅读笔记)-13.代理模式

news2024/12/22 19:00:35

监控糖果机

假设现在需要一台监视器去生成报告,报告中包括糖果机的位置、库存等信息

// 糖果机
public class GumballMachine{
    String loc;
    public GumballMachine(String loc, int count){
        this.loc = loc;
    }
    public String getLoc(){
        return loc;
    }
    // 其他方法省略
}
// 监视器
public class GumballMonitor{
       GumballMachine gumballMachine;
       public GumballMonitor(GumballMachine gumballMachine){
           this.gumballMachine = gumballMachine;
       }
       public void report(){
           System.out.println(gumballMachine,getLoc());
           // 打印其余数据
       }
}
// 开始测试
public class GumballMachineTest{
       public static void main(String[] agrs){
           GumballMachine gumballMachine = new GumballMachine(args[0], Integer.parseInt(args[1]));
           GumballMonitor gumballMonitor = new GumballMonitor(gumballMachine);
           gumballMonitor.report();
       }
}

此时客户想要远程监控糖果机,意味着无法直接将糖果机对象直接传给监视器对象,该怎么办?不如创建一个代理对象,通过该对象实现远程调用。对于客户而言,看起来在做远程调用,实际是调用本地的代理对象,代理对象通过网络去调用真正的糖果机


代理模式

  • 为另一个对象提供一个替身或占位符以控制对该对象的访问
  • 被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象
  • 代理模式有多种实现,如糖果机监视器属于远程代理
  • 代理模式类图如下所示,其中:

在这里插入图片描述


远程监控糖果机-远程代理

书中涉及到Java RMI,这里不再叙述,大致过程如下图所示:

在这里插入图片描述

显示CD封面-虚拟代理

当创建一个对象开销较大时就可以使用虚拟代理,该代理在真正需要一个对象的时候会被创建。真正的对象在创建前和创建中时,虚拟代理作为对象的替身;对象创建好后,代理就会把请求委托给对象

现在想要从网站上获取CD封面,但是加载图像需要一定时间,在等待时间中应该显示一些其他内容,等下载完成后就显示下载好的封面


class ImageProxy implements Icon{  // Icon接口定义了获取Icon属性、打印Icon等方法
    ImageIcon imageIcon;  // 真正对象,也实现了Icon接口
    URL imageURL;
    public ImageProxy(URL url){
        imageURL = url;  // 图像的下载网址
    }
    
    public int geyIconWidth(){
        // 真正Icon已经下载完成,就去获取真实数值
        if(imageIcon != null){
            return imageIcon.getIconWidth();
        }else{
            return 100;  // 还没下载完成就返回一个自定义数值
        }
    }
    // 其余方法类似,对于下载完成和为完成采用两种方式
}

动态代理

在完成下面的配对服务前,需要先了解什么是动态代理

  • Java可用java.lang.reflect包在运行时动态地创建代理类,实现一或多个接口,并将方法的调用转发到指定的类,因为实际的代理类是在运行时创建的,称该技术为动态代理
  • 因为此时Proxy类不是自己实现的,所以不能将代码放在Proxy类中,而是将代码放在InvacationHandler中,它响应代理的任何调用

在这里插入图片描述


配对服务-保护代理

保护代理可以根据访问权限决定客户能否访问对象

现在想要完成一项配对服务,别人可以约会对象进行打分

// 每个参与配对用户需要实现的接口
public interface PersonBean{
       String getName();
       int getHotOrNotRating();
       void setName();
       void setHotOrNotRating(int rating);
    // 其他属性的getter和setter省略
}
// 某个参与配对的用户
public class PersonBeanImpl implements PersonBean{
       String name;
       int rating;
       int ratingCount = 0;
       // 计算当前用户收到评分的平均值
       public int getHotOrNotRating(){
           if(ratingCount == 0){
               return 0;
           }
           return (rating / ratingCount);
       }
       // 统计当前用户收到评分的总值和给其评分的人数
       public void setHotOrNotRating(int rating){
           this.rating += rating;
           ratingCount++;
       } 
}

但是该系统需要满足当前用户可以修改个人信息,但是不能修改别人给自己的评分,其他用户可以给当前用户评分,但是不能修改当前用户的个人信息,该如何实现?需要创建两个代理,一个访问自己的PersonBean对象,另一个访问其他客户的PersonBean对象


  • 创建两个InvocationHandlerInvocationHandler实现代理的行为,Java负责创建真实的代理类和对象,自己提供handler(在方法调用时知道该做什么):

在这里插入图片描述

// 客户看自己bean时(也就是查看自己信息)
public class OwnerInvocationHandler implements InvocationHandler{
    PersonBean personBean;
    public OwnerInvocationHandler(PersonBean person){
        this.person = person;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throw IllegalAccessException{
        try{
            // 客户可以获取自己所有信息
            if(method.getName().startWith("get")){
                return method.invoke(person, agrs);
                // 客户不允许修改自己评分
            }else if(method.getName().startWith("setHotOrNotRating")){
                throw new IllegalAccessException();
                // 允许设置其他个人信息,比如年龄等
            }else if(method.getName().startWith("set")){
                return method.invoke(person, agrs);
            }
        }catch(InvocationTargetException e){
            e.printStackTrace();
        }
        return null;
    }
}
  • 创建动态Proxy类:该方法定义在测试类中
// 创建客户自己的代理
PersonBean getOwnerPorxy(PersonBean person){
    return (PersonBean)Proxy.newProxyInstance(
    	person.getClass().getClassLoader(),
    	person.getClass().getInterfaces(),
        new OwnerInvocationHandler(person)
    );
}
// 创建其他人的代理
PersonBean getNonOwnerPorxy(PersonBean person){
    return (PersonBean)Proxy.newProxyInstance(
    	person.getClass().getClassLoader(),
    	person.getClass().getInterfaces(),
        new NonOwnerInvocationHandler(person)
    );
}
  • 开始测试:
public class MatchMakingTest{
    public static void main(String[] args){
        MatchMakingTest test = new MatchMakingTest();
        test.drive();
    }
    public void drive(){
        PersonBean psj = getPersonFromDatabase("psj");  // 从数据库中获取psj信息
        // 下面两个代理的realSubject都是psj对象
        PersonBean ownerProxy = getOwnerPorxy(psj);  // 创建客户自己的代理
        ownerProxy.setHotOrNotRating(10);  // 报错
        PersonBean nonOwnerProxy = getNonOwnerPorxy(psj);  // 创建其他人的代理
        ownerProxy.setName("xxx");  // 报错
    }
}

参考

Head First 设计模式-代理模式

设计模式-代理模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/77673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详解Pytorch中的torch.nn.MSELoss函数(包括每个参数的分析)

一、函数介绍 Pytorch中MSELoss函数的接口声明如下,具体网址可以点这里。 torch.nn.MSELoss(size_averageNone, reduceNone, reduction‘mean’) 该函数默认用于计算两个输入对应元素差值平方和的均值。具体地,在深度学习中,可以使用该函数用…

玩转webpack(03):webpack进阶使用

一、自动清理构建目录 避免构建前每次都要手动删除dist 使用 clean-webpack-plugin(默认删除output指定的输出目录) (1)依赖安装 npm i clean-webpack-plugin -D (2)使用 --- webpack.prod.js const Cl…

基于java学生签到考勤系统

开发工具eclipse,jdk1.8 技术:java swing 数据库:mysql5.7 学生选课系统功能:管理员、教师、学生三个角色 一、管理员功能: 1.登录、修改密码、退出系统 2.学生管理:添加、修改、删除、查询 3.班级管理&#x…

YOLOV1算法学习记录

前言 R-CNN系列算法(R-CNN、SPPNet、Fast R-CNN、Faster R-CNN)均是采用two-stage的方法(1.提取region proposal 2.分类边框回归),主要是对region proposal进行识别定位。虽然这类方法检测精度很高,但由于…

Leetcode番外篇——滑动窗口的应用

各位好,博主新建了个公众号《自学编程村》,拉到底部即可看到,有情趣可以关注看看哈哈,关注后还可以加博主wx呦~~~(公众号拉到底部就能看到呦) 我们刚刚在上一节讲述了TCP的滑动窗口。殊不知,它…

基于RISC-V的Copy-On-Write

为什么需要写时拷贝呢? 当 shell执行指令的时候会 fork(),而这个 fork()出来的进程首先会调用的就是 exec来执行对应的命令,如果我们将 fork()创建的进程对地址空间进行了完整的拷贝,那将是一个巨大的消耗 因为在实际应用中,for…

微信小程序框架-全面详解(学习总结---从入门到深化)

小程序与普通网页开发的区别 小程序的主要开发语言是 JavaScript ,小程序的开发同普通的网页 开发相比有很大的相似性。对于前端开发者而言,从网页开发迁移 到小程序的开发成本并不高,但是二者还是多少有些许区别的,例如&#xff…

HCIP实验 4-1:路由引入与路由控制

实验 4-1 路由引入与路由控制 学习目的 掌握OSPF与ISIS相互路由引入的配置方法掌握通过地址前缀列表过滤路由信息的配置方法掌握通过Route-policy过滤路由信息的配置方法 拓扑图 场景 你是你们公司的网络管理员。公司网络中有两部分路由区域,一部分运行OSPF,另外…

【Proteus仿真】【51单片机】厨房天然气泄漏检测报警系统

文章目录一、功能简介二、软件设计三、实验现象联系作者一、功能简介 本项目使用Proteus8仿真51单片机控制器,使用LCD1602、按键、天然气、烟雾传感器、ADC,报警模块等。 系统运行后,LCD1602显示传感器检测的天然气浓度和烟雾浓度值。 可通…

中国土地交易数据库:300w数据中国土地高频交易数据2000-2022

土地交易是土地在流通过程中多方发生的经济关系,土地交易的行为主要是交换的土地所有权、使用权、租赁权、抵押权等。在我国,土地作为一种重要资源,其收购储备和交易行为都由国家进行统一管理。经过改革开放几十年的探索和实践,土…

手机投影到电脑显示 此设备不支持miracast,因此不能以无线投影到它

在家里使用手机的体感游戏,发现手机屏幕比较小,想要将其投影到自己的笔记本电脑上,这样看得就比较大了。然后我就打开笔记本电脑,操作如下: 如下图: 原文地址:手机投影到电脑显示 此设备不支持miracast,因此不能以无线投影到它 - 廖强的博客 但是结果我们就看到了…

Mysql安装配置和Mysql使用六千字详解!!

目录 课前导读 一、Mysql的安装和配置 二、数据库简介: 1、数据库中典型代表: 2、数据库类型: 3、Mysql简介: 4、客户端和服务器简介: 三、初始MySQL 四、数据库操作 五、表的基本操作 六、表的基础增删查改…

虚拟主机、WordPress 主机和云主机之间的区别

💂 个人网站:【海拥】【摸鱼游戏】【神级源码资源网站】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 想寻找共同学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】💬 免费且…

[附源码]JAVA毕业设计校园失物招领管理系统(系统+LW)

[附源码]JAVA毕业设计校园失物招领管理系统(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目…

港科夜闻|罗康锦教授获委任为香港科大工学院院长

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、罗康锦教授获委任为香港科大工学院院长。该委任任期由2023年1月1日开始。罗康锦教授服务香港科大多年,是智慧交通系统、智慧城市和可持续发展的杰出学者,在学术研究方面屡获殊荣。罗教授拥有丰富的学…

阿里巴巴内部最新发布SpringCloud ALiBaBa全彩版

就在昨天,阿里巴巴发布了最新的SpringCloud ALiBaBa全解第三版同时也是全彩版,话不多说我们直接来看干货! 由于文章的篇幅有限,下面只能为大家展示目录内容,需要领取完整版可以文末免费获取章节目录 微服务介绍 微服务…

Go 实现插入排序算法及优化

Go 实现插入排序算法及优化插入排序算法实现算法优化小结耐心和持久胜过激烈和狂热。 哈喽大家好,我是陈明勇,今天分享的内容是使用 Go 实现插入排序算法。如果本文对你有帮助,不妨点个赞,如果你是 Go 语言初学者,不妨…

python基于SVM的疫情评论情感数据分析

1、构建SVM情感分析模型 读取数据 使用pandas的库读取微薄数据读取并使进行数据打乱操作 import pandas as pd test pd.read_csv(".\\weibo.csv") test_data pd.DataFrame(test)[:1000] test_data 打乱数据 re_test_data test_data.sample(frac1).reset_index(…

代码随想录训练营第44天|完全背包、LeetCode 518. 零钱兑换 II、 377. 组合总和 Ⅳ

完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。 完全背包和01背包问题唯一不同…

前端工程化实践——快速入门treeshaking

treeshaking treeshaking本质是去除多余代码算法。在前端的性能优化中,es6 推出了tree shaking机制,tree shaking就是当我们在项目中引入其他模块时,他会自动将我们用不到的代码,或者永远不会执行的代码摇掉,在…