23种设计模式笔记第八篇代理模式(参考狂神视频)

代理模式(Proxy)

有两种代理模式:静态代理、动态代理

动态代理分为两大类:基于接口的动态代理(例如JDK动态代理)

                                    基于类的动态代理(例如Cglib代理)

                                    可以去了解一下JAVAssist(字节码类库)

实际上想到中介就简单多了,代理就相当于中介

静态代理

角色分析:

抽象角色:一般会使用接口或者类来解决(租房)

真实角色:被代理的角色(房东)

代理角色:代理真实的角色,代理真实角色后,一般会做一些附属操作,比如中介有收取中介费的操作(中介)

客户:访问代理对象的人(租房的人)

一个房东可能只出租一套房,但是中介可以代理n套房子,也就是说可以接进来n多个接口

UML类图

  代码实现:

首先创建一个抽象的租房接口

//租房
public interface Rent {
	public void rent();
}

创建真实角色(房东实现租房接口)

//房东
public class Host implements Rent {
	@Override
	public void rent() {
		System.out.println("房东要出租房子");
	}
}

创建代理角色(中介实现租房接口)

//中介
public class Proxy implements Rent {
	//使用组合
	private Host host;//房东
	
	public Proxy() {
	}
	
	public Proxy(Host host) {
		this.host = host;
	}
	
	@Override
	public void rent() {
		host.rent();
	}
	
	//中介这里不仅可以租房,还可以看房
	public void seeHouse() {
		System.out.println("中介带你看房");
	}
	
	//收中介费
	public void fare() {
		System.out.println("中介收中介费");
	}
	
	//签租赁合同
	public void hetong() {
		System.out.println("中介签合同");
	}
}

创建客户访问代理角色

//客户端:要租房的人
public class Client {
	public static void main(String[] args) {
		Host host = new Host();
		//代理,代理角色一般会有一	些附属操作
		Proxy proxy = new Proxy(host);
		//你不用面对房东,直接找中介租房子即可
		proxy.rent();
	}
}

静态代理模式的优缺点

优点:

1)可以使真实角色的操作更加纯粹,不用去关注一些公共的业务

2)公共业务就交给了代理角色,实现了业务的分工

3)公共业务发生扩展的时候,方便集中管理

缺点:(可以使用动态代理解决)

一个真实角色就会产生一个代理角色,代码量会翻倍(例如租房的房东,卖车的车主等)

静态代理模式实现2

在公司里,修改原来的代码是大忌

public interface UserService {
	public void add();
	public void delete();
	public void update();
	public void query();
}
//真实对象
public class UserServiceImpl implements UserService {

	@Override
	public void add() {
		System.out.println("增加了一个用户");
	}

	@Override
	public void delete() {
		System.out.println("删除了一个用户");
	}

	@Override
	public void update() {
		System.out.println("修改了一个用户");
	}

	@Override
	public void query() {
		System.out.println("查询了一个用户");
	}
	
}
//代理角色
public class UserServiceProxy implements UserService {
	private UserServiceImpl userService;
	
	public void setUserService(UserServiceImpl userService) {
		this.userService = userService;
	}

	@Override
	public void add() {
		log("add");
		userService.add();
	}

	@Override
	public void delete() {
		log("delete");
		userService.delete();
	}

	@Override
	public void update() {
		log("update");
		userService.update();
	}

	@Override
	public void query() {
		log("query");
		userService.query();
	}

	public void log(String msg) {
		System.out.println("[info]使用了"+msg+"方法");
	}
}
public class Client {
	public static void main(String[] args) {
		UserServiceImpl userService = new UserServiceImpl();
		UserServiceProxy proxy = new UserServiceProxy();
		proxy.setUserService(userService);
		proxy.query();
	}
}

动态代理模式(这里以JDK动态代理为例)

角色分析(与静态代理角色一样)

动态代理的代理类是动态生成的,不是我们直接写好的!

动态代理的本质就是反射机制实现的

首先要了解两个类:Proxy:代理;InvocationHandler:调用处理程序

InvocationHandler:是反射包下的接口,每个代理实例都有一个关联的调用处理程序。利用代理实例自动生成,InvocationHandler接口里仅仅只有一个方法invoke(proxy,method,args)处理代理实例上的方法调用,并返回结果。

Proxy:提供了创建动态代理类和实例的静态方法,也是由这些方法创建的所有动态代理的超类。里面有四个静态方法,这里用到了newProxyInstance(loader,interfaces,h)生成一个代理对象其参数为(类加载器来定义代理类,代理类实现的接口列表,调度方法调用的调用处理函数)

UML类图:

代码如下:

首先我们还是要有一个接口Rent

//租房
public interface Rent {
	public void rent();
}

创建真实对象

//房东
public class Host implements Rent {
	@Override
	public void rent() {
		System.out.println("房东要出租房子");
	}
}

创建代理处理程序类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//这是一个处理程序,并不是一个真实的代理类
//反射包下的,不要导错包
public class ProxyInvocationHandler implements InvocationHandler{

	//被代理的接口
	private Rent rent;
	
	public void setRent(Rent rent) {
		this.rent = rent;
	}
	
	//生成得到代理类
	public Object getProxy() {
		//(代理人,被代理对象)
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
	}
	
	//处理代理实例,并返回结果
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		seeHouse();
		//动态代理的本质,就是使用反射机制实现
		Object result = method.invoke(rent, args);
		hetong();
		fare();
		return result;
	}
	
	//中介这里不仅可以租房,还可以看房
	public void seeHouse() {
		System.out.println("中介带你看房");
	}
	
	//收中介费
	public void fare() {
		System.out.println("中介收中介费");
	}
	
	//签租赁合同
	public void hetong() {
		System.out.println("中介签合同");
	}

}

测试

public class Client {
	public static void main(String[] args) {
		//真实角色
		Host host = new Host();
		//代理角色,现在没有
		ProxyInvocationHandler pih = new ProxyInvocationHandler();
		//通过调用程序处理角色来处理我们要调用的接口对象
		pih.setRent(host);
		//这里的proxy就是动态生成的 ,我们并没有写
		Rent proxy = (Rent)pih.getProxy();
		proxy.rent();
	}
}

 动态代理模式的优化

我们可以将动态代理处理程序类弄成一个工具类

public class ProxyInvocationHandler implements InvocationHandler{

	//被代理的接口
	private Object target;
	
	public void setTarget(Object target) {
		this.target = target;
	}
	
	//生成得到代理类
	public Object getProxy() {
		//(代理人,被代理对象)
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
	}
	
	//处理代理实例,并返回结果
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = method.invoke(target, args);
		return result;
	}
}

然后在客户端中:

public class Client {
	public static void main(String[] args) {
		//真实角色
		UserServiceImpl userService = new UserServiceImpl();
		//代理角色,现在不存在
		ProxyInvocationHandler pih = new ProxyInvocationHandler();
		//设置要代理的对象
		pih.setTarget(userService);
		//动态生成代理类
		UserService proxy = (UserService)pih.getProxy();
		
		proxy.delete();
	}
}

动态代理模式的优缺点

优点:

1)可以使真实角色的操作更加纯粹,不用去关注一些公共的业务

2)公共业务就交给了代理角色,实现了业务的分工

3)公共业务发生扩展的时候,方便集中管理

4)一个动态代理类代理的是一个接口,一般就是对应的一类业务

5)一个动态代理类可以代理多个类,只要实现了同一个接口即可

动态代理模式和静态代理模式的区别说一个例子就很好理解了,现在是一个房东一个中介,那如果有两个房东呢?我们就需要一个与之对应的中介了,否则不符合开闭原则

代理模式的应用场景 

如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:

1、修改原有的方法来适应。这样违反了开闭原则。

2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。

使用代理模式,可以将功能划分的更加清晰,有助于后期维护!

代理模式与适配器模式

都是借助第三方去访问目标对象

适配器模式的重点在于衔接不同类型的类或接口

代理模式的重点在于处理不同类之间的逻辑实现

猜你喜欢

转载自blog.csdn.net/qq_44709970/article/details/124642774