静态代理模式
在 Java 中,静态代理模式是一种常见的设计模式,它可以在不修改目标对象代码的前提下,对目标对象的功能进行增强。在多线程场景下,静态代理模式同样适用,下面将详细介绍 Java 多线程中的静态代理模式。
1. 静态代理模式的基本概念
静态代理模式包含三个主要角色:
- 抽象主题(Subject):定义了目标对象和代理对象的共同接口,通常是一个接口或抽象类。
- 真实主题(RealSubject):实现了抽象主题接口,是实际要执行任务的对象。
- 代理主题(ProxySubject):也实现了抽象主题接口,持有真实主题的引用,在调用真实主题的方法前后可以添加额外的逻辑。
2. 多线程中的静态代理模式示例
下面通过一个简单的多线程示例来演示静态代理模式的使用。假设我们要实现一个线程任务,该任务的功能是打印一段信息,同时在任务执行前后添加一些额外的日志信息。
步骤 1:定义抽象主题接口
// 抽象主题接口
interface Task {
void execute();
}
步骤 2:定义真实主题类
// 真实主题类,实现 Task 接口
class RealTask implements Task {
@Override
public void execute() {
System.out.println("正在执行任务...");
try {
// 模拟任务执行时间
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务执行完成。");
}
}
步骤 3:定义代理主题类
// 代理主题类,实现 Task 接口
class TaskProxy implements Task {
private Task realTask;
public TaskProxy(Task realTask) {
this.realTask = realTask;
}
@Override
public void execute() {
System.out.println("任务开始前的准备工作...");
// 调用真实主题的方法
realTask.execute();
System.out.println("任务完成后的清理工作...");
}
}
步骤 4:使用代理主题类创建线程并执行任务
public class StaticProxyInMultithreading {
public static void main(String[] args) {
// 创建真实主题对象
RealTask realTask = new RealTask();
// 创建代理主题对象,并将真实主题对象传入
TaskProxy taskProxy = new TaskProxy(realTask);
// 创建线程并传入代理主题对象
Thread thread = new Thread(taskProxy::execute);
// 启动线程
thread.start();
}
}
3. 代码解释
- 抽象主题接口
Task
:定义了一个execute()
方法,该方法是任务执行的核心方法。 - 真实主题类
RealTask
:实现了Task
接口,具体实现了execute()
方法,模拟了一个耗时的任务。 - 代理主题类
TaskProxy
:也实现了Task
接口,持有一个Task
类型的引用realTask
。在execute()
方法中,先输出任务开始前的准备信息,然后调用真实主题的execute()
方法,最后输出任务完成后的清理信息。 - 主类
StaticProxyInMultithreading
:创建了真实主题对象和代理主题对象,将代理主题对象的execute()
方法作为线程的任务,启动线程执行任务。
上面看不懂没关系,我这里有个简单的例子
我们就以结婚这件事情来分析,首先结婚人是真实主题类,婚礼公司是代理主题类(负责除了结婚外的事情,比如准备现场),那我们的抽象主题接口就是结婚。
注意四个要素:
- 接口
- 主要人物
- 代理人物
- 主类(就是放main方法的地方)
其中接口是主要人物和代理人物都要实现的,是主要事件,区别在于主要人物只用实现主要事件,而代理人物可以在重写接口方法的过程中做一些别的事情。
主要事件(结婚):用接口表示
interface Marry {
void marry();
}
主要人物(结婚人):只用重写结婚,并只写结婚
class Person implements Marry {
private String name;
public Person(String name) {
this.name = name;
}
public Person() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void marry() {
System.out.println("今天是"+name+"结婚的日子");
}
}
代理人物(婚礼公司):负责婚前和婚后的处理,但是结婚期间就是婚礼人进行,即在婚礼公司的重写方法中代用结婚人的重写方法,类似多态。
class MarryCompany implements Marry {
private Marry Marry_Person;
public MarryCompany(Marry Marry_Person) {
this.Marry_Person = Marry_Person;
}
public MarryCompany() {}
public Marry getMarry_Person() {
return Marry_Person;
}
public void setMarry_Person(Marry marry_Person) {
Marry_Person = marry_Person;
}
@Override
public void marry() {
before(); // 结婚前的操作
Marry_Person.marry(); // 这里就是婚礼公司调用结婚人的重写
after(); // 结婚后的操作
}
public void before() {
System.out.println("结婚前准备场景");
}
public void after() {
System.out.println("结婚后善后");
}
}
完整代码:
package com.demo01;
interface Marry {
void marry();
}
class Person implements Marry {
private String name;
public Person(String name) {
this.name = name;
}
public Person() {}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void marry() {
System.out.println("今天是"+name+"结婚的日子");
}
}
class MarryCompany implements Marry {
private Marry Marry_Person;
public MarryCompany(Marry Marry_Person) {
this.Marry_Person = Marry_Person;
}
public MarryCompany() {}
public Marry getMarry_Person() {
return Marry_Person;
}
public void setMarry_Person(Marry marry_Person) {
Marry_Person = marry_Person;
}
@Override
public void marry() {
before();
Marry_Person.marry();
after();
}
public void before() {
System.out.println("结婚前准备场景");
}
public void after() {
System.out.println("结婚后善后");
}
}
public class staticProxy {
public static void main(String[] args) {
Person p = new Person("6<7");
MarryCompany mc = new MarryCompany(p);
// 直接调用而不启用多线程
mc.marry();
// //使用多线程,创建线程并传入代理主题对象
// Thread thread = new Thread(mc::marry);
// // 启动线程
// thread.start();
}
}
疑问解答(必看***)
看到这里的伙伴可能会有些疑问,在这里解答一下难懂点:
-
文中类似多态的解释:类似多态就是,婚礼公司里有一个接口对象,而且是通过这个接口对象去接受结婚人,是不是类似多态的父类引用指向子类,然后调用的是子类的方法marry()。
-
代理的工作:这样的话我们在主类里面是不是先创建结婚人对象,然后把结婚人对象传给婚礼公司,然后婚礼公司在重写marry方法中调用结婚人的marry。
-
关于开启多线程:开启的话这个marry方法就在新线程中执行,而主线程继续执行。两个线程同时进行。
-
关于如何开启多线程:创建一个Thread对象,将要执行的任务(在这里即是婚礼公司重写的marry方法)给线程,怎么给呢?将实例化对象下的marry方法给线程,类似Thread thread = new Thread(mc::marry),其中mc是婚礼公司,
::
可以理解为在什么下的,这里就可以翻译成这个线程执行在mc下的marry方法。 -
开启与不开启多线程的区别:开启就是新线程与主线程并发执行,不开启就是直接在主线程代用mc的marry方法。