設計模式之代理模式——用java示範

一、前言

1、代理模式概念

爲一個對象提供一個替身,以控制對這個對象的訪問,即通過代理對象訪問目標對象(被代理對象),這樣做的好處:可以在目標對象實現的基礎上,增強額外的功能操作,即擴展目標對象的功能。
被代理對象可以是遠程對象、創建開銷大的對象和需要安全控制的對象。

2、分類

java中的代理模式分爲三種:靜態代理、動態代理(JDK代理、接口代理)、Cglib代理。
其中Cglib代理有些書上也把它歸爲了動態代理。

二、示例

1、靜態代理

在靜態代理當中,不管是被代理對象(也稱目標對象),還是代理對象,都需要去實現共同的接口(或者是繼承共同的父類)。

優點: 在不修改目標對象功能的前提下,能夠通過代理對象對目標功能進行擴展。
缺點: 因爲代理對象與目標對象需要實現相同的接口,所以會有很多代理類。

UML類圖如下圖所示:
(其中TeacherDao是被代理對象,TeacherDaoProxy是代理對象)
在這裏插入圖片描述
代碼

  1. ITeacherDao.java
public interface ITeacherDao 
{
	public abstract void teach();
}
  1. TeacherDao.java
public class TeacherDao implements ITeacherDao
{
	@Override
	public void teach() 
	{
		System.out.println("老師正在上課。。。。。");		
	}
}
  1. TeacherDaoProxy.java
public class TeacherDaoProxy implements ITeacherDao
{
	private ITeacherDao dao;
	public TeacherDaoProxy(ITeacherDao dao)
	{
		this.dao=dao;
	}
	@Override
	public void teach() 
	{
		System.out.println("準備上課。。。");
		dao.teach();
		System.out.println("結束上課。。。");
	}

}

  1. Client.java
public class Client 
{
	public static void main(String[] args) 
	{
		TeacherDaoProxy teacherDaoroxy=new TeacherDaoProxy(new TeacherDao());
		teacherDaoroxy.teach();
	}
}
2、動態代理(JDK代理、接口代理)

動態代理與靜態代理比較明顯的一個區別是,動態代理中的代理對象不需要去實現接口,僅要求目標對象(亦稱被代理對象)去實現接口。

代理對象的生成是利用JDK的API,動態地在內存中構建對象。
用到的是java.lang.reflect.Proxy這個類中的一個靜態方法newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h),
該方法接收三個參數,分別是:
loader - 定義代理類的類加載器
interfaces - 代理類要實現的接口列表
h - 指派方法調用的調用處理程序

UML類圖如下:
在這裏插入圖片描述
代碼:

  1. ITeacherDao.java
public interface ITeacherDao 
{
	void teach();
}
  1. TeacherDao.java
public class TeacherDao implements ITeacherDao
{
	@Override
	public void teach() 
	{
		System.out.println("教師正在上課。。。");		
	}
}
  1. ProxyFactory.java
public class ProxyFactory 
{
	private Object target;
	public ProxyFactory(Object target)
	{
		this.target=target;
	}	
	public Object getProxyInstance()
	{
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
					{
						System.out.println("開始上課。。。");
						Object object=method.invoke(target, args);
						System.out.println("結束代理。。。");
						return object;
					}
				}
				);
	}
}
  1. Client.java
public class Client 
{
	public static void main(String[] args) 
	{
		ITeacherDao dao=new TeacherDao();
		ProxyFactory factory=new ProxyFactory(dao);
		ITeacherDao instance=(ITeacherDao)factory.getProxyInstance();
		instance.teach();
	}
}

3、Cglib代理

Cglib代理與前面兩種代理不同的是,目標對象不需要去實現接口,它使用目標對象的子類來實現代理,Cglib代理也稱爲子類代理,有些書也將其歸爲動態代理。

Cglib是一個強大的高性能的代碼生成包,它可以在運行期擴展java類與實現java接口,被許多AOP框架使用,例如Spring AOP,實現方法攔截。

Cglib包的底層使用字節碼處理框架ASM來轉換字節碼並生成新的類。

要想使用Cglib代理,首先得導入jar包(共4個),引入依賴。點我下載jar包 。密碼:c6ca

Cglib代理的UML類圖如下:
在這裏插入圖片描述
代碼:

  1. TeacherDao.java
public class TeacherDao 
{
	public String teach()
	{
		System.out.println("老師正在授課中……Cglib代理,目標對象無需實現接口!");
		return "hello";
	}
}
  1. ProxyFactory.java
public class ProxyFactory implements MethodInterceptor
{
	private Object target;
	public ProxyFactory(Object target)
	{
		this.target=target;
	}
	public Object getProxyInstance()
	{
		Enhancer enhancer=new Enhancer();//創建一個工具類
		enhancer.setSuperclass(target.getClass());//設置父類
		enhancer.setCallback(this);//設置回調函數
		return enhancer.create();//創建子類對象,即代理對象
	}
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable 
	{
		System.out.println("代理開始~");
		Object object=arg1.invoke(target, arg2);
		System.out.println("代理結束~");
		return object;
	}

}
  1. Client.java
public class Client 
{
	public static void main(String[] args) 
	{
		ProxyFactory proxyFactory=new ProxyFactory(new TeacherDao());
		TeacherDao teacherDao=(TeacherDao)proxyFactory.getProxyInstance();
		String string=teacherDao.teach();
		System.out.println("方法的返回值:"+string);		
	}
}
三、總結
  1. 靜態代理中,目標對象和代理對象都需要實現接口。
  2. 動態代理中,目標對象需要實現接口。
  3. Cglib代理中,目標對象不需要實現接口。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章