【设计模式】代理模式

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/smile_running

    代理模式(Proxy Pattern),是非常贴近我们生活的一个例子,我们实际生活中比比皆是,很多服务行业基本都是和代理相挂钩的。举个例子,比如银行的业务人员,这个我们最熟悉不过了,要去银行办理一些业务的时候,通常都会叫你去找业务代理人员,或者称为业务办理人员,他们所用的就是代理模式,把银行的业务交给业务员去代理。类似这种的销售模式,不仅限于银行,像很多销售楼房、车辆等都一样。

    再有就是和计算机息息相关的代理也有很多,比如代理 ip、代理服务器,还有一些代理软件等等。不过代理模式还可以分为两种,一种是:静态代理,另一种是:动态代理

    关于这些事例就介绍到此,我们来看看今天要用的代理模式的定义:一个类代表另一个类的功能,这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。为其他对象提供一种代理以控制对这个对象的访问。

    了解了一些关于代理模式的知识,我们就可以很快的步入今天的案例。这里呢,以我要去买房的这个例子,来运用代理模式写一下相关代码。

  • 静态代理

    话说这一天,我来到了一家售楼公司里面了解楼盘情况,等到你一进门呢,很多售楼小姐姐就会围上来,口若悬河的向你逐个的介绍楼盘情况。这时候呢,小姐姐通常都是非常热情的,因为只要你买了套房,她们的提成也是挺高的。不过这不是我们关心的,我们应该关心的是这个售楼小姐姐,她在这个例子当中担任什么样的角色。

    思考一番,原来她是代理人,她所拥有的技能就是销售各种各样的楼房。好吧,扯完了,代码可以写起来了,来看我们的代理接口,也就是代理人所拥有的技能。

package com.xww.dp.proxy;

/**
 * 代理业务接口,有出售小区房、别墅的业务功能,得到的收益不一样。
 * 
 * @author xww
 *
 */
public interface SalesProxy {

	int sellHouse();// 出售小区房

	int sellVilla();// 出售别墅
}

接下来就是这个接口的实现类,也就是向我们销售的小姐姐,这个类需要实现刚刚创建的接口,代表着她拥有了这个能力。

package com.xww.dp.proxy;

/**
 * 推销员,销售楼房的人。做为你的代理人。
 * 
 * @author xww
 *
 */
public class Salesmen implements SalesProxy {

	public Salesmen() {

	}

	@Override
	public int sellHouse() {
		System.out.println("销售员:向你推荐了 1 套小区房,1800000元");
		return 1800000;
	}

	@Override
	public int sellVilla() {
		System.out.println("销售员:向你推荐了 1 套别墅,价格:9000000元");
		return 9000000;
	}
}

    以上数据都为瞎编了,那么既然销售人员是代理人,那么我们自己就是被代理的对象,我们的能力是买房子、考虑要买什么样的房子,就这两个简单的方法,代码如下:

package com.xww.dp.proxy;

/**
 * 我们自己,被代理的对象,通过代理人购买房子
 * 
 * @author xww
 *
 */
public class Me {

	private Salesmen salesmen;

	public Me(Salesmen salesmen) {
		super();
		this.salesmen = salesmen;
	}

	public void think() {
		int money = salesmen.sellVilla();
		System.out.println("我:又不是土豪,买不起,买不起!");
	}

	public void buy() {
		int money = salesmen.sellHouse();
		System.out.println("我:就这个了,付了" + money + "元");
	}

}

    因为我们要通过代理人,才能知道一些楼房的相关信息及价格。所以呢,在上面的 Me 类要传入代理人(小姐姐0)的引用,这样我们才能获取到想要的信息。好了,这就是我们的静态代理模式的相关代码,接下来运行看看吧。

客户端代码:

package com.xww.dp.proxy;

/**
 * 静态代理模式
 * 
 * @author xww
 * @博客:https://blog.csdn.net/smile_running
 */
public class StaticProxyClient {

	public static void main(String[] args) {

		Salesmen salesmen = new Salesmen();
		Me me = new Me(salesmen);

		me.think();
		me.buy();
	}

}

    第一次呢,小姐姐向我们推荐了一套别墅,额、你看我像买得起别墅的样子嘛!!然后呢,又给我推荐了一间小区房,我呢就果断的买下来了。

【设计模式】代理模式_第1张图片

    好了,买完房子结束了,开开心心的回了家。静态代理模式就是这样的,看上去代码比较简单,也容易理解。首先我们作为代理人,是没有房源信息的,也就是这个售楼人员,让我们间接的有了房源的信息,就体现了一个类拥有了另一个类的功能,这就是代理模式的概念。

    动态代理也是如此,让一个类代表另一个类,让它间接的拥有另一个类的功能。下面我们来看看动态代理是怎么样实现的。

  • 动态代理

    动态代理,是 Jdk 为我们提供的一个方式,对应的类名就叫做 Proxy 类,在 java.lang.reflect 包下面。动态代理理解起来可能有一点困难,看它这个包,就知道动态代理运用的是反射来实现的。

    下面呢,我们就使用动态代理模式修改一下代码,看看会有哪一些变化。首先这个 Proxy 类的用法我就不再进行介绍了吧,这个是 Java 基础,与静态代理不同的是,动态代理必须是一个接口类,不是接口还行,因为 Proxy 类要求我们传入的是一个 interface 类型的,这里要对上面的 Me 类进行修改,必须实现接口才行,代码如下:

package com.xww.dp.proxy;

/**
 * 我们自己,被代理的对象,通过代理人购买房子
 * 
 * @author xww
 *
 */
public class Me implements SalesProxy {

	public Salesmen salesmen;

	public Me(Salesmen salesmen) {
		super();
		this.salesmen = salesmen;
	}

	@Override
	public int sellHouse() {
		int money = salesmen.sellVilla();
		System.out.println("我:又不是土豪,买不起,买不起!");
		return 0;
	}

	@Override
	public int sellVilla() {
		int money = salesmen.sellHouse();
		System.out.println("我:就这个了,付了" + money + "元");
		return 0;
	}

}

    我们把 think() 和 buy() 方法干掉了,留下接口里面的方法即可。因为动态代理反射回来的是一个接口类型,所以我们调用的只能是接口里面的抽象方法,来看我们的具体方法:

package com.xww.dp.proxy;

import java.lang.reflect.Proxy;

/**
 * 动态代理。注意: 1、被代理对象必须实现代理的接口
 * 
 * @author xww
 *
 */
public class DynamicProxyClient {

	public static void main(String[] args) {

		Salesmen salesmen = new Salesmen();
		Me me = new Me(salesmen);

		SalesProxy mProxy = (SalesProxy) Proxy.newProxyInstance(
				SalesProxy.class.getClassLoader(),
				new Class[] { SalesProxy.class }, new SalesHandler(me));

		mProxy.sellHouse();
		mProxy.sellVilla();
	}
}

    我们实例化了一个 me 对象,并且把它传到了 SalesHandler 里面,因为我们要调用 Salesmen 类的方法,必须要传进去。来看看代码:

package com.xww.dp.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理 - 处理类
 * 
 * @author xww
 *
 */
public class SalesHandler implements InvocationHandler {

	private Me me;

	public SalesHandler(Me me) {
		this.me = me;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] params)
			throws Throwable {

		Object obj = method.invoke(me, params);
		return obj;
	}

}

    这里通过 method 调用对象里面的方法,返回的就是一个接口类型,最后 ruturn 回去就是我们的 SalesProxy 接口的对象,拿到该实例已经,就可以调用接口里面的方法了。那么,它的输出也一样如下:

【设计模式】代理模式_第2张图片

     那么至此,动态代理也就写完了。通过对比代码,静态代理和动态代理所使用的方式有所不同,前者是正常的 new 对象,然后调用方法,后者则是通过反射的方式实例化对象,然后才可以调用方法。而且一般来说,动态代理所写的代码,或者是需求增加时要改变的代码量而言,会比静态代理少。

    好了,代理模式的两种实现方式就是这样了,那么要怎么选择就需要你根据实际的需求来决定了。

你可能感兴趣的:(趣味设计模式)