设计模式(二十一)Proxy模式
在面向对象编程中,“本人”和“代理人”都是对象。如果“本人”对象太忙了,有些工作无法自己亲自完成,就将其交给“代理人”对象负责。
示例程序的类图。
示例程序的时序图。从这个时序图可以看出,直到调用print方法,开始进入实际打印阶段后,PrinterProxy类才会生成Printer类的实例。
package bigjunoba.bjtu.proxy; public interface Printable {
public abstract void setPrinterName(String name);
public abstract String getPrinterName();
public abstract void print(String string);
}
Printable接口用于是PrinterProxy类和Printer类具有一致性。三个方法分别用来设置打印机的名字、获取打印机的名字和显示文字(打印输出)。
package bigjunoba.bjtu.proxy; public class Printer implements Printable { private String name; public Printer() {
heavyJob("正在生成Printer的实例");
} public Printer(String name) {
this.name = name;
heavyJob("正在生成Printer的实例(" + name + ")");
} private void heavyJob(String msg) {
System.out.println(msg);
for (int i = 1; i < 4; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("生成阶段" + i);
}
System.out.println("结束。");
} @Override
public void setPrinterName(String name) {
this.name = name;
} @Override
public String getPrinterName() {
return name;
} @Override
public void print(String string) {
System.out.println("===" + name + "====");
System.out.println(string);
} }
Printer类是表示“本人”的类。在该类的构造函数中,heavyJob方法表示一个干3秒的“重活”,它每秒以一个阶段指示显示工作进度。
package bigjunoba.bjtu.proxy; public class PrinterProxy implements Printable { private String name;
private Printer real; public PrinterProxy() {
} public PrinterProxy(String name) {
this.name = name;
} @Override
public synchronized void setPrinterName(String name) {
if (real != null) {
real.setPrinterName(name);
}
this.name = name;
} @Override
public String getPrinterName() {
return name;
} @Override
public void print(String string) {
realize();
real.print(string);
} private synchronized void realize() {
if (real == null) {
real = new Printer(name);
}
} }
PrinterProxy类是扮演“代理人”的角色的类,是Proxy模式的核心。name字段保存了打印机的名字,而real字段中保存的是“本人”。
setPrinterName方法用于设置新的打印机名字。如果real字段不为空,也就是说已经生成了“本人”,那么就会设置“本人”的名字。但是当real字段为空时,也就是说还没有生成“本人”,那么只会设置自己PrinterProxy实例的名字。getPrinterName方法返回自己PrinterProxy实例的名字。
print方法已经超出了代理人的工作范围,即real字段为空时,也就是没有本人实例因此它会调用realize方法来生成本人。在调用realize方法后,real字段中只会保存本人Printer类的实例,因此可以调用real.print方法。这就是“委托”。
这里要理解的就是,Printer类不知道PrinterProxy类的存在。即Printer类并不知道自己到底是通过PrinterProxy被调用的还是直接被调用的。
但是反过来说,PrinterProxy类是知道Printer类的。这是因为PrinterProxy类的real字段是Printer类型的。即PrinterProxy类是与Printer类紧密关联在一起的组件。
还要注意的是synchronized关键字:
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
package bigjunoba.bjtu.proxy; public class Main {
public static void main(String[] args) {
Printable printable = new PrinterProxy("LianJiang");
System.out.println("现在的名字是" + printable.getPrinterName() + "。");
printable.setPrinterName("QiaoJiang");
System.out.println("现在的名字是" + printable.getPrinterName() + "。");
printable.print("SB");
}
}
Main方法很简单,主要就是要验证一下是否只有在调用print方法时才会生成Printer实例。
现在的名字是LianJiang。
现在的名字是QiaoJiang。
正在生成Printer的实例(QiaoJiang)
生成阶段1
生成阶段2
生成阶段3
结束。
===QiaoJiang====
SB
结果很明显,“代理人”帮助“本人”做了set和get名字的工作,而print工作只有“本人”能做,所以只有让本人来做。
解释一下Proxy模式的类图:
1.Subject(主体):定义了使Proxy和RealSubject之间具有一致性的接口。由于存在Subject,因此Client不必在意它所使用的究竟是Proxy还是RealSubject。
2.Proxy(代理人):尽量处理来自Client的请求,只有当自己不能处理时,才会将工作交给RealSubject。Proxy只有在必要时才会生成RealSubject。
3.RealSubject(实际的主体):“本人”会在“代理人”无法胜任工作时出场。
4.Client(请求者):使用Proxy模式。
Proxy模式的一些应用:
1.在Proxy模式中,代理人尽力肩负着工作使命。在示例程序中,成功地将耗时处理推迟到print方法被调用才进行。在一个大型系统的初始化过程中,存在大量的耗时处理,如果在启动系统时连那些暂时不会被使用的功能也初始化了,那么应用程序的启动时间会很长,这将会引发用户的不满。只要在有需要的时候将某个功能初始化就可以大大减少启动时间。
2.代理和委托:当代理人不能解决问题时,就会“转交”给本人去解决,这里的“转交”就是“委托”。
3.透明性:是指Main类可以完全不用在意调用的是本人类还是代理人类。
4HTTP代理:HTTP代理是指位于Web服务器和Web浏览器之间,为Web页面提供高速缓存等功能的软件。这也是一种Proxy模式。在通过Web浏览器访问Web页面时,并不会每次都去访问远程Web服务器来获取页面的内容,而是会先去获取HTTP代理缓存的页面。只有当需要最新页面内容或是页面的缓存期限过期时,才去访问远程Web服务器。
设计模式(二十一)Proxy模式的更多相关文章
- 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)
设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...
- C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获得任何对理解该模式有用的 ...
- C#设计模式之十一外观模式(Facade)【结构型】
一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...
- php设计模式(二):结构模式
上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式. 一.什么是结构型模式? 结构型模式是解析类和对象的内部结构和外部组 ...
- Java进阶篇设计模式之十一 ---- 策略模式和模板方法模式
前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...
- Java设计模式之十一 ---- 策略模式和模板方法模式
前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...
- JavaScript设计模式(二):工厂模式
工厂模式模式的定义与特点 工厂模式(Factory Pattern)是编程中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.在工厂模式中,我们在创建对象时不会对 ...
- 设计模式 ( 二十一 ):Vistor访问者模式 -- 行为型
1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有 ...
- 十、设计模式之代理(Proxy)模式
什么是代理模式 代理模式是对象的结构模式,为其他对象提供一种对象以控制对这个对象的访问. 代理模式的结构图如下:(源自大话设计模式) Subject:定义了RealSubject和Proxy的公共 ...
- Head First 设计模式 —— 13. 代理 (Proxy) 模式
思考题 如何设计一个支持远程方法调用的系统?你要怎样才能让开发人员不用写太多代码?让远程调用看起来像本地调用一样,毫无瑕疵? P435 已经接触过 RPC 了,所以就很容易知道具体流程:客户端调用目标 ...
随机推荐
- .Net Reactor混淆导致匿名类处理出现的问题处理分析
.Net Reactor 是一款比较不错的混淆工具,比VS自带的那个好用很多,一直以来也陪伴着我们的成长,虽然没有完美的混淆工具,不过也算还是不错的,至少能在一定程度上对DLL进行一定的保护处理. 不 ...
- [LeetCode] 822. Card Flipping Game
Description On a table are N cards, with a positive integer printed on the front and back of each ca ...
- [PHP] php, apache, VS Code安装与配置
1. 下载
- MongoDB 学习笔记之 查询表达式
查询表达式: db.stu.find().count() db.stu.find({name: 'Sky'}) db.stu.find({age: {$ne: 20}},{name: 1, age: ...
- SpringBoot-ElasticJob封装快速上手使用(分布式定时器)
elastic-job-spring-boot qq交流群:812321371 1 简介 Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Ela ...
- ui自动化测试
一.梳理 1.根据要求需要自动添加很多条数据 2.这就涉及到ui方面的知识.元素定位的方法(这个就能遇到很多坑,要完全掌握元素定位才能避免进坑).循环等(代码基础要掌握好) 二.操作 选择进行自动化操 ...
- Docker 安装Oracle
1.使用docker 命令搜索oracle 镜像,前提是已安装了Docker docker search oracle 2.下载相应版本的oracle 镜像 docker pull sath89/o ...
- e课表项目第二次冲刺周期第一天
昨天干了什么? 昨天与我们小组的成员商量了一个重大的决定,由于我们第一次冲刺周期的成果,就是我们决定我们要转型发展. 今天干了什么? 查阅相关的资料,我们正式决定要做一款学习的课程表APP,把简易作为 ...
- 2. SOFAJRaft源码分析—JRaft的定时任务调度器是怎么做的?
看完这个实现之后,感觉还是要多看源码,多研究.其实JRaft的定时任务调度器是基于Netty的时间轮来做的,如果没有看过Netty的源码,很可能并不知道时间轮算法,也就很难想到要去使用这么优秀的定时调 ...
- 彻底修改eclipse中项目的名称
需要四个步骤: 一.右键工程:Refactor->Rename,或选中工程按F2,修改名称 二.修改项目目录下:.project文件 三.项目右键属性 --> Web Project Se ...