java 開發模式之十三 : 代理模式

原理或定義

提供了對目標對象另外的訪問方式;即通過代理對象訪問目標對象.這樣做的好處是: 可以在目標對象實現的基礎上增強額外的功能操作即擴展目標對象的功能

代理模式又分爲靜態代理和動態代理。靜態代理是由程序猿創建或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。動態代理是在程序運行時,通過運用反射機制動態的創建而成。

結構

抽象角色:聲明真實對象和代理對象的共同接口。
代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當於對真實對象進行封裝。
真實角色:代理角色所代表的真實對象,是我們最終要引用的對象

類圖

案例與代碼

本文使用遠程糖果機監控項目作爲遠程代理的案例

監控糖果機:地點、糖果庫存和當前狀態


遠程代理:遠程對象的本地代表,通過它可以讓遠程對象當本地對象來調用。遠程代理通過網絡和真正的遠程對象溝通信息。

利用Java RMI實現遠程代理:


RMI遠程方法調用是計算機之間通過網絡實現對象調用的一種通訊機制。
使用這種機制,一臺計算機上的對象可以調用另外 一臺計算機上的對象來獲取遠程數據。

RMI開發步驟:

製作遠程接口:接口文件
遠程接口的實現:Service文件
RMI服務端註冊,開啓服務
RMI代理端通過RMI查詢到服務端,建立聯繫,通過接口調用遠程方法

被監控的機器類:

public class CandyMachine extends UnicastRemoteObject implements CandyMachineRemote{

	State mSoldOutState;
	State mOnReadyState;
	State mHasCoin;
	State mSoldState;
	State mWinnerState;
	private String location="";
	private State state;
	private int count = 0;

	public CandyMachine(String location,int count) throws RemoteException{
		this.location=location;
		this.count = count;
		mSoldOutState = new SoldOutState(this);
		mOnReadyState = new OnReadyState(this);
		mHasCoin = new HasCoin(this);
		mSoldState = new SoldState(this);
		mWinnerState = new WinnerState(this);
		if (count > 0) {
			state = mOnReadyState;
		} else {
			state = mSoldOutState;
		}
	}
	public String getLocation()
	{
		return location;
	}
	public void setState(State state) {
		this.state = state;
	}

	public void insertCoin() {
		state.insertCoin();
	}

	public void returnCoin() {
		state.returnCoin();
	}

	public void turnCrank() {
		state.turnCrank();
		state.dispense();
	}

	void releaseCandy() {

		// TODO Auto-generated method stub
		if (count > 0) {
			count = count - 1;
			System.out.println("a candy rolling out!");
		}

	}

	public int getCount() {
		return count;
	}

	public void printstate() {
		state.printstate();
	}
	public State getstate() {
		return state;
	}
}
此類的設計沿用狀態模式的設計方法。


客戶端類:

public class RemoteMainTest {
	public static void main(String[] args) {

		try {
			CandyMachine service = new CandyMachine("test1", 7);
			// LocateRegistry.createRegistry(6602);
			Naming.rebind("rmi://127.0.0.1:6602/test1", service);
			service.insertCoin();
			service = new CandyMachine("test2", 5);
			Naming.rebind("rmi://127.0.0.1:6602/test2", service);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println(e.toString());
		}

	}
}




代理接口:

import java.rmi.Remote;
import java.rmi.RemoteException;

import com.java.jikexueyuan.agentmode.candymachine.State;

public interface CandyMachineRemote extends Remote{
	public String  getLocation() throws RemoteException;
	public int getCount() throws RemoteException;
	public State getstate() throws RemoteException;
}


管理類/ 監控類:

public class Monitor {

	private ArrayList<CandyMachineRemote> candyMachinelst;

	public Monitor() {
		candyMachinelst = new ArrayList<CandyMachineRemote>();
	}

	public void addMachine(CandyMachineRemote mCandyMachine) {
		candyMachinelst.add(mCandyMachine);
	}

	public void report() {
		CandyMachineRemote mCandyMachine;
		for (int i = 0, len = candyMachinelst.size(); i < len; i++) {
			mCandyMachine = candyMachinelst.get(i);
			try {
				System.out
						.println("Machine Loc:" + mCandyMachine.getLocation());

				System.out.println("Machine Candy count:"
						+ mCandyMachine.getCount());
				System.out.println("Machine State:"
						+ mCandyMachine.getstate().getstatename());
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}

測試類:

public class MainTest {

	public static void main(String[] args) {
		Monitor mMonitor = new Monitor();

		try {
			CandyMachineRemote mCandyMachine = (CandyMachineRemote) Naming
					.lookup("rmi://127.0.0.1:6602/test1");
			mMonitor.addMachine(mCandyMachine);
			mCandyMachine = (CandyMachineRemote) Naming
					.lookup("rmi://127.0.0.1:6602/test2");
			mMonitor.addMachine(mCandyMachine);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		mMonitor.report();
	}

}




使用場景

1 遠程代理,也就是爲一個對象在不同的地址空間提供局部代表,這樣可以隱藏一個對象存在於不同地址空間的事實

2、虛擬代理,是根據需要創建開銷很大的對象,通過它來存放實例化需要很長時間的真實對象。這樣就可以達到性能的最優化,比如圖片對象。

3、安全代理,控制真實對象訪問時的權限。一般用於對象應該有不同的訪問權限的時候

4、指針引用,是指當調用真實的對象時,代理處理另外一些事。比如計算真實對象的引用次數,這樣當該對象沒有引用時,可以自動釋放它,或當第一次引用一個持久對象時,將它裝入內存,或是在訪問一個實際對象前,檢查是否已經釋放它,以確保其他對象不能改變它。這些都是通過代理在訪問一個對象時附加一些內務處理

5、延遲加載,用代理模式實現延遲加載的一個經典應用就在 Hibernate 框架裏面。當 Hibernate 加載實體 bean 時,並不會一次性將數據庫所有的數據都裝載。

優缺點

主要優點有:

1代理對象作爲客戶端和目標對象之間的中介,起到了保護目標對象的作用

缺點主要有

1由於在客戶端和真實主題之間增加了代理對象,會造成請求的處理速度變慢;

2實現代理模式需要額外的工作(有些代理模式的實現非常複雜),從而增加了系統實現的複雜度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章