一、代理设计模式
根据模式是用来完成什么工作来划分,这种方式可分为创建型模式、结构型模式和行为型模式 3 种。
代理设计模式属于三种的的:结构型模式(用于描述如何将类或对象按某种布局组成更大的结构)。
1.代理模式的定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
2.组成
-
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。(一般是用接口或抽象类来解决)
-
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。(代理真实角色,代理角色一般会做一些其他的操作)
-
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。 (被代理的角色)
3.优点
-
职责清晰:
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。(可以让真实对象职责更明确!不去关注一些公共的业务) -
代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。(公共的业务交给了代理角色,实现了业务的分工)
-
高扩展性。(公共业务发生扩展时(加需求),方便集中管理)
二、租房案例
对象:房东(Renter )、中介(Proxy)
出租事件:Rent接口的rent()方法,用于出租。
关系:中介(代理对象)可以代理房东(真实对象)租房子。
1.抽象角色
抽象角色:代理角色(代理人)和真实角色可以实现)
这里抽象角色为一个接口:出租方法,用于出租房屋。
/** 房东Host和代理人中介Proxy都可以实现出租Rent这件事情(方法) */
public interface Rent {
/** 出租房屋 */
void rent();
}
2.真实角色
真实角色:真实的角色,可以实现业务方法.
真实角色房东,可以实现出租房屋。房东仅仅只用关注出租房屋。
/** 房东:可以出租房屋的人 */
public class Renter implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子。");
}
}
3.代理角色
代理角色:是真实对象的代理,也可以实现业务方法。
代理角色中介,不仅可以实现代理角色出租房屋,他还可以在租房前做一些别的事情。比如看房,签合同
/** 代理人中介 */
public class Proxy implements Rent {
private Renter host;
public Proxy(Renter host) {
this.host = host;
}
@Override
public void rent() {
before();
host.rent();
after();
}
private void before() {
System.out.println("----- 中介带你看房 -----");
}
private void after() {
System.out.println("----- 中介带你签合同 -----");
}
}
4.测试
有一个租客需要租房子,租客找中介租到了房子。
中介代理了房东,帮房东出租了房子,还帮房东做一些别的事情,比如看房,签合同。职责明确。
同时,代理还保护了真实的房东信息(对目标对象进行保护)。
/** 租客:需要租房子的人 */
public class Tenant {
/** 顾客去租房 */
public static void main(String[] args) {
// 找到中介(中介代理了某个房东)
Proxy proxy = new Proxy(new Renter());
// 找中介租房子
proxy.rent();
}
}
输出:
可以看到中介(代理对象)帮房东(真实对象)出租了房子,同时还帮房东解决了一些其他的问题。
----- 中介带你看房 -----
房东出租房子。
----- 中介带你签合同 -----
三、真实业务案例
需求:
增加业务日志输出功能:业务调用前需要输出调用的方法名,调用后需要输出返回值。
1.抽象角色
抽象角色:用户增删改查操作接口。
/** 用户数据访问层接口 */
public interface UserDao {
void ins();
void del();
void upd();
void sel();
}
2.真实角色
真实对象:用户增删改查操作接口的实现类。
public class UserDaoImpl implements UserDao {
@Override
public void ins() {
System.out.println("insert命令");
}
@Override
public void del() {
System.out.println("delete命令");
}
@Override
public void upd() {
System.out.println("update命令");
}
@Override
public void sel() {
System.out.println("select命令");
}
}
3.代理角色
代理对象:用于代理真实角色,让真实角色职责更清晰明确。
/** 增加业务日志打印:调用前需要输出调用的方法名,调用后需要输出返回值 */
public class UserDaoImplProxy implements UserDao {
private UserDao userDao;
public void setUserDaoImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void ins() {
log("----- 执行了ins()方法 -----");
userDao.ins();
log("----- 无返回值 -----");
}
@Override
public void del() {
log("----- 执行了del()方法 -----");
userDao.del();
log("----- 无返回值 -----");
}
@Override
public void upd() {
log("----- 执行了upd()方法 -----");
userDao.upd();
log("----- 无返回值 -----");
}
@Override
public void sel() {
log("----- 执行了sel()方法 -----");
userDao.sel();
log("----- 无返回值 -----");
}
/** 日志 */
private void log(String name) {
System.out.println("[info]: "+name);
}
}
4.测试
创建代理对象,放入需要代理的真实对象,调用业务方法。
public class Test {
public static void main(String[] args) {
// 代理对象,新增日志打印
UserDaoImplProxy userDaoProxy = new UserDaoImplProxy();
// 代理原本对象UserDaoImpl
userDaoProxy.setUserDaoImpl(new UserDaoImpl());
// 执行方法
userDaoProxy.ins();
userDaoProxy.del();
userDaoProxy.upd();
userDaoProxy.sel();
}
}
输出:
可以看到真实对象UserDaoImpl被代理对象UserDaoImplProxy给代理了,并且实现了新增的业务。
[info]: ----- 执行了ins()方法 -----
insert命令
[info]: ----- 无返回值 -----
[info]: ----- 执行了del()方法 -----
delete命令
[info]: ----- 无返回值 -----
[info]: ----- 执行了upd()方法 -----
update命令
[info]: ----- 无返回值 -----
[info]: ----- 执行了sel()方法 -----
select命令
[info]: ----- 无返回值 -----
四、备注
通过上面,我们大概了解了静态代理,但是静态代理有个缺点。
静态代理缺点 :每一个真实对象会产生一个代理角色,代码量会翻倍,开发效率变低(静态代理是在编译期就已经确定代理类和真实类的关系,并且生成代理类的)。
但是有方法解决的!使用 动态代理 (动态代理是在运行期利用JVM的 反射 机制生成代理类,这里是直接生成类的字节码,然后通过类加载器载入JAVA虚拟机执行)!
相关
我的该分类的其他相关文章,请点击:【Spring + Spring MVC + MyBatis】文章目录