文章目录
- 前言
- 一、代理模式中的三大角色
- 二、静态代理引入
- 1.业务接口
- 2.目标对象
- 总结
前言
在Java程序中代理模式的作用:
- 当一个对象需要收到保护的时候可以考虑使用代理对象去完成某个行为
- 需要给某个对象的功能进行功能增强的时候,可以考虑找一个代理进行增强
- A对象无法和B对象直接交互时,也可以使用代理模式来解决
一、代理模式中的三大角色
第一个角色:目标对象(演员)
第二个角色:代理对象(替身演员)
第三个角色:目标对象和代理对象的公共接口(演员和替身演员应该具有相同的行为动作)
使用代理模式的话,对于客户端程序来说,客户端是无法察觉到的,客户端在使用代理对象的时候就像在使用目标对象
二、静态代理引入
1.业务接口
OrderService
public interface OrderService {
void generate();
void modify();
void detail();
}
2.目标对象
OrderServiceImpl (原业务实现类)
public class OrderServiceImpl implements OrderService{
@Override
public void generate() {
//模拟生成订单的耗时
try{
Thread.sleep(1234);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("订单已生成");
}
@Override
public void modify() {
try{
Thread.sleep(1234);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("订单已修改");
}
@Override
public void detail() {
try{
Thread.sleep(1234);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("查看订单详情");
}
}
需求:
项目经理提出一个新的业务需求:需要统计所有业务接口中每一个业务方法的耗时。
解决方案一:硬编码,在每一个业务接口中的每一个业务方法中直接添加统计耗时的程序
缺点一:违背OCP开闭原则
缺点二:代码没有得到复用(相同的代码写了很多遍)
解决方案一修改之后的代码
public class OrderServiceImpl implements OrderService{
@Override
public void generate() {
long begin = System.currentTimeMillis();
//模拟生成订单的耗时
try{
Thread.sleep(1234);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("订单已生成");
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
@Override
public void modify() {
long begin = System.currentTimeMillis();
try{
Thread.sleep(443);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("订单已修改");
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
@Override
public void detail() {
long begin = System.currentTimeMillis();
try{
Thread.sleep(546);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("查看订单详情");
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
}
测试程序:
public class Test {
public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
orderService.generate();
orderService.detail();
orderService.modify();
}
}
解决方案二:编写业务类的子类,让子类继承业务类,对每个业务方法进行重写
缺点一:虽然解决了OCP开闭原则,但是这种方式会导致耦合度很高,因为采用了继承关系。继承关系是一种耦合度高的关系,不建议使用
缺点二:代码没有得到复用(相同的代码写了很多遍)
**添加新的子类OrderServiceSub **
之前的业务实现类保持不变
public class OrderServiceSub extends OrderServiceImpl{
@Override
public void generate() {
long begin = System.currentTimeMillis();
super.generate();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
@Override
public void modify() {
long begin = System.currentTimeMillis();
super.modify();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
@Override
public void detail() {
long begin = System.currentTimeMillis();
super.detail();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
}
测试程序:
public class Test {
public static void main(String[] args) {
OrderService orderService = new OrderServiceSub();
orderService.generate();
orderService.detail();
orderService.modify();
}
}
解决方案三:代理模式
优点一:解决了OCP问题
优点二:采用代理模式的has a,可以降低耦合度
缺点一:如果有一百个业务接口需要写一百个代理类,会造成类爆炸,不好维护,可以使用动态代理来解决这个问题。动态代理还是代理模式,只不过添加了字节码生成技术,可以在内存中为我们动态的生成一个class字节码,这个字节码就是代理类。
代理模式中的代理对象OrderServiceProxy
对于静态代理来说,OrderService就是公共接口,OrderServiceImpl就是目标对象,缺少代理对象。
代理对象和目标对象要有相同的行为,就要实现同一个或同一些接口
客户端在使用代理对象的时候就像在使用目标对象一样
将目标对象作为代理对象的一个属性,这种关系叫做关联关系,比继承关系的耦合度低
private OrderService target;//这就是目标对象,目标对象一定是实现了OrderService接口
注意:这里要写一个公共接口类型,因为公共接口耦合度低,不能写实现类。通过构造方法赋值
public class OrderServiceProxy implements OrderService{
//将目标对象作为代理对象的一个属性,这种关系叫做关联关系,比继承关系的耦合度低
private OrderService target;//这就是目标对象,目标对象一定是实现了OrderService接口
public OrderServiceProxy(OrderService target) {
this.target = target;
}
@Override
public void generate() {
long begin = System.currentTimeMillis();
//调用目标对象的目标方法
target.generate();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
@Override
public void modify() {
long begin = System.currentTimeMillis();
target.modify();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
@Override
public void detail() {
long begin = System.currentTimeMillis();
target.detail();
long end = System.currentTimeMillis();
System.out.println("耗时"+(end-begin)+"毫秒");
}
}
测试程序:
public class Test {
public static void main(String[] args) {
//new OrderServiceImpl()目标对象
//new OrderServiceProxy()代理对象
OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());
//调用代理对象的代理方法
orderService.generate();
orderService.modify();
orderService.detail();
}
}
总结
类和类之间的关系,包括6种关系,其中两个关系是:
- 泛化关系
- 关联关系
泛化关系:继承 is a
Cat is a animal
public class Animal(){}
public class Cat extends Animal(){}
关联关系:has a
张三 has a 苹果
public class Person(){
private Apple apple;
}
public class Apple(){}
相比来说:泛化关系的耦合度高于关联关系