设计模式——代理模式

代理模式,是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间祈祷中介的作用,代理模式属于结构型设计模式。使用代理模式主要有两个目的:一是保护对象,二是增强目标对象

1.静态代理

首先先举一个简单的例子
创建顶层接口Person:

public interface Person {
	public void findLove();
}

创建son类

public class Son implements Person {

	@Override
	public void findLove() {
		// TODO Auto-generated method stub
		System.out.println("儿子");
	}

}

创建father类

public class Father {
	private Son son;
	
	public Father(Son son) {
		this.son = son;
	}
	
	public void findLove() {
		System.out.println("父亲前置");
		this.son.findLove();
		System.out.println("父亲后置");
	}

}

进行测试

public static void main(String []args) {
		Father father = new Father(new Son());
		father.findLove();
}

测试结果

父亲前置
儿子
父亲后置

下面结合业务代码进行进一步演示
先创建Order订单类

public class Order {
	private Object orderInfo;
	private Long createTime;
	private String id;
	public Object getOrderInfo() {
		return orderInfo;
	}
	public void setOrderInfo(Object orderInfo) {
		this.orderInfo = orderInfo;
	}
	public Long getCreateTime() {
		return createTime;
	}
	public void setCreateTime(Long createTime) {
		this.createTime = createTime;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	
	

}

创建持久层操作类

public class OrderDao {
	
	public int insert(Order order) {
		System.out.println("OrderDao创建order成功");
		return 1;
	}

}

创建Service接口

public interface OrderService {
	
	int createOrder(Order order);

}

创建service接口实现

public class OrderServiceImp implements OrderService {
	
	private OrderDao orderdao;
	
	public OrderServiceImp() {
		this.orderdao = new OrderDao();
	}

	@Override
	public int createOrder(Order order) {
		System.out.println("Imp调用Dao创建订单");
		return orderdao.insert(order);
	}

}

接下来先创建数据路由对象,使用ThreadLocal的单例实现

public class DynamicDataSourceEntry {
	public static final String DEFAULT_SOURCE = null;
	private static final ThreadLocal<String> local = new ThreadLocal<String>();
	private DynamicDataSourceEntry() {}
	
	//清空数据源
	public static void clear() {
		local.remove();
	}
	
	//获取当前使用数据源的名字
	public static String get() {
		return local.get();
	}
	
	//还原当时切换的数据源
	public static void restore() {
		local.set(DEFAULT_SOURCE);
	}
	
	//设置已知名字的数据源
	public static void set(String source) {
		local.set(source);
	}
	
	//根据年份动态设置数据源
	public static void set(int year) {
		local.set("DB"+year);
	}

}

创建切换数据源代理类

public class OrderServiceStaticProxy implements OrderService {
	
	private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
	
	private OrderService orderService;
	
	public OrderServiceStaticProxy(OrderService orderService) {
		this.orderService =orderService;
	}

	@Override
	public int createOrder(Order order) {
		before();
		Long time = order.getCreateTime();
		Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
		System.out.println("当前使用【DB_"+dbRouter+"】数据库");
		DynamicDataSourceEntry.set(dbRouter);
		orderService.createOrder(order);
		after();
		return 0;
	}
	
	private void before() {
		System.out.println("before method");
	}
	
	private void after() {
		System.out.println("after method");
	}

}

进行测试

public class DbRouterTest {
	
	public static void main(String args[]) {
		try {
			Order order = new Order();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
			Date date =sdf.parse("2017/02/01");
			order.setCreateTime(date.getTime());
			OrderService os = new OrderServiceStaticProxy(new OrderServiceImp());
			os.createOrder(order);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

}

测试结果如下

before method
当前使用【DB_2017】数据库
Imp调用Dao创建订单
OrderDao创建order成功
after method

2.动态代理

动态代理和静态代理基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩张适应性更强

1.JDK实现方式

首先对第一个例子进行改造

public class Customer implements Person {

	@Override
	public void findLove() {
		// TODO Auto-generated method stub
		System.out.println("客户");
	}

}
public class JDKMiPo implements InvocationHandler {
	//被代理的对象,把引用保存下来
	private Object target;
	
	public Object getInstance(Object target) {
		this.target= target;
		Class<?> clazz = target.getClass();
		return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(), this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		before();
		Object obj = method.invoke(this.target,args);
		after();
		return null;
	}
	
	private void before() {
		System.out.println("前置方法");
	}
	private void after() {
		System.out.println("后置方法");
	}

}
public class JDKDynamicTest {
	
	public static void main(String args[]){
		try {
			Person obj = (Person) new JDKMiPo().getInstance(new Customer());
			obj.findLove();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

}

测试结果

前置方法
客户
后置方法

下面对另一实例进行优化

public class OrderServiceStaticProxy implements InvocationHandler  {
	
	private SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
	
	private Object target;
	
	public Object getInstance(Object target) {
		this.target= target;
		Class<?> clazz = target.getClass();
		return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(), this);
	}

	
	private void before(Object target) {
		try {
			Long time = (Long) target.getClass().getMethod("getCreateTime").invoke(target);
			Integer dbRouter = Integer.valueOf(yearFormat.format(new Date(time)));
			System.out.println("当前使用【DB_"+dbRouter+"】数据库");
			DynamicDataSourceEntry.set(dbRouter);
		}catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	private void after() {
		System.out.println("after method");
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		before(args[0]);
		Object obj = method.invoke(target, args);
		after();
		return obj;
	}

}
public class DbRouterTest {
	
	public static void main(String args[]) {
		try {
			Order order = new Order();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
			Date date =sdf.parse("2017/02/01");
			order.setCreateTime(date.getTime());
			OrderService os = (OrderService) new OrderServiceStaticProxy().getInstance(new OrderServiceImp());
			os.createOrder(order);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

}

测试结果如下

当前使用【DB_2017】数据库
Imp调用Dao创建订单
OrderDao创建order成功
after method

2.JDK代理实现原理

JDK动态代理采用字节重组,重新生成对象来代替原始对象,以达到动态代理的目的。JDK动态代理生成对象的步骤如下:
1.获取被代理对象的引用,并获取他的所有接口,反射获取
2.JDK代理重新生成一个类,同时新的类要实现被代理类的所有接口
3.动态生成Java代码,新加的业务逻辑代码由一定的逻辑代码调用
4.编译生成Java代码.class文件
5.重新加载到JVM中运行

3.静态代理和动态代理的本质区别

1.静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,代理类需要同步增加,违背开闭原则
2.动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则
3.若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需新增策略就可完成,无需修改代码

4.代理模式的优缺点

代理模式具有以下优点:
1.代理模式能将代理对象与真是被调用对象分离
2.在一定程度上降低了系统的耦合性,扩展性好
3.可以起到保护对象的功能
4.可以增强对象的功能
但也有缺点
1.代理模式会导致系统设计中类的数量增加
2.在客户端和目标对象间加了一个对象,导致请求速度变慢
3.增加了系统的复杂度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值