代理模式
概述
在日常生活中我们经常听到代理这个词语,它指的是代替别人进行工作。当有一些功能不需要“本人”亲自工作时,可以让代理人进行工作,但是有一些特殊的功能需要“本人”亲自工作时,那这些功能会交给“本人”实现。
示例程序
在示例程序中,我们模仿大老板签字,只有特定的文件需要大老板签字时,小老板才会将文件交给他,其余的文件小老板可以全权负责,可以理解为小老板是大老板的代理。
UML类图
名字 | 说明 |
---|---|
Boss | 大老板类 |
Bossable | Boss和BossProxy的实现接口 |
BossProxy | 小老板类 |
代码实现
Bossable
public interface Bossable {
String getPrintName();//获取名称
void setPrintName(String name);//设置名称
void print(String str);//签名
}
Boss
public class Boss implements Bossable{
private String name;
public Boss() {
heavyJob("正在生成Boss实例");
}
public Boss(String name) {
this.name = name;
heavyJob("正在生成Boss实例{" + name + "}");
}
@Override
public String getPrintName() {
return name;
}
@Override
public void setPrintName(String name) {
this.name = name;
}
@Override
public void print(String str) {
System.out.println("====" + name + "====");
System.out.println(str);
}
private void heavyJob(String msg){
System.out.println(msg);
System.out.println("end");
}
}
BossProxy
@NoArgsConstructor
public class BossProxy implements Bossable{
private String name;
private Boss boss;
public BossProxy(String name) {
this.name = name;
}
@Override
public String getPrintName() {
return name;
}
@Override
public synchronized void setPrintName(String name) {
if (boss != null){
boss.setPrintName(name);
}
this.name = name;
}
@Override
public void print(String str) {
realize();
boss.print(str);
}
private synchronized void realize(){
if (boss == null){
boss = new Boss(name);
}
}
}
test
@SpringBootTest
class Practice1500ApplicationTests {
@Test
void contextLoads() {
Bossable proxy = new BossProxy("章副总");
//还未生成boss实例
System.out.println(proxy.getPrintName());
proxy.setPrintName("张副总");
System.out.println(proxy.getPrintName());
//生成boss实例
System.out.println("===============================");
proxy.print("正版签名");
}
}
//结果
章副总
张副总
===============================
正在生成Boss实例{张副总}
end
====张副总====
正版签名
参与角色
-
Subject(主体)
Subject定义了使Boss和BossProxy角色之间具有一致性的接口,由于存在Subject角色,调用者不必在意他使用的时Boss还是BossProxy,在示例程序中由Bossable扮演该角色
-
Proxy(代理人)
Proxy角色会尽量完成调用者交给他的任务,出现实在完成不了的任务才会交给本人去处理,在示例程序中由BossProxy扮演。
-
RealSubject(实际的主体)
RealSubject角色会在Proxy角色处理不了任务的时候才会出现,在示例程序中由Boss扮演。
习题
习题一
在示例程序中,BossProxy类知道Boss类的存在,请修改BossProxy类,让其不必知道Boss
修改BossProxy
@NoArgsConstructor
public class BossProxy implements Bossable{
private String name;
private Bossable boss;
private String className;
public BossProxy(String name,String className) {
this.name = name;
this.className = className;
}
@Override
public String getPrintName() {
return name;
}
@Override
public synchronized void setPrintName(String name) {
if (boss != null){
boss.setPrintName(name);
}
this.name = name;
}
@Override
public void print(String str) {
realize();
boss.print(str);
}
private synchronized void realize(){
if (boss == null){
try {
boss = (Bossable) Class.forName(className).newInstance();
boss.setPrintName(name);
} catch (Exception e) {
System.out.println("找不到" + className + "类");
}
}
}
}
习题二
在示例程序中,BossProxy类中setPrintName方法和realize方法都使用synchronized修饰,如果不适用synchronized会带来什么问题?
synchronized对这块方法加锁,如果在不加锁的情况下,多线程访问时很有可能出现BossProxy和Boss中的name属性不同
总结
其实小黄刚开始接触时,也觉得代理模式并没有什么必要,我们完全可以通过RealSubject角色来直接调用各种方法。
其实代理模式可以避免资源的浪费,假设我们创建Boss的过程非常的复杂,所有的复杂操作全部都在print方法中,这样在初始化的时候程序就会非常的慢。而Proxy角色成功将Boss的初始化方法推迟到了调用print方法时。