Proxy是比較有用途的一種模式,而且變種較多,應用場合覆蓋從小結構到整個系統的大結構,Proxy是代理的意思,我們也許有代理服務器等概念,代理概念可以解釋為:在出發點到目的地之間有一道中間層,意為代理.
設計模式中定義: 為其他對象提供一種代理以控制對這個對象的訪問.要用再建立
程序舉例1:權限訪問
public class ForumProxy implements Forum {
private ForumPermissions permissions; private Forum forum; this.authorization = authorization;
public ForumProxy(Forum forum, Authorization authorization, ForumPermissions permissions) { this.forum = forum; this.authorization = authorization; this.permissions = permissions; }
.....
public void setName(String name) throws UnauthorizedException, ForumAlreadyExistsException { //只有是系統或論壇管理者才可以修改名稱 if (permissions.isSystemOrForumAdmin()) { forum.setName(name); } else { throw new UnauthorizedException(); } }
...
}
|
而DbForum才是接口Forum的真正實現,以修改論壇名稱為例:
public class DbForum implements Forum, Cacheable { ...
public void setName(String name) throws ForumAlreadyExistsException {
....
this.name = name; //這里真正將新名稱保存到數據庫中 saveToDb();
.... }
...
}
|
凡是涉及到對論壇名稱修改這一事件,其他程序都首先得和ForumProxy打交道,由ForumProxy決定是否有權限做某一樣事情,ForumProxy是個名副其實的"網關","安全代理系統".
程序舉例2:用到才創建
實際執行打印 為了模仿長時間操作 在構建的時候延遲5S
public class Printer implements Printable {
private String name;
public Printer() {
heavyJob("正在產生Printer的對象實例");
}
public Printer(String name) { // 構造子
this.name = name;
heavyJob("正在產生Printer的對象實例(" + name + ")");
}
public void setPrinterName(String name) { // 命名
this.name = name;
}
public String getPrinterName() { // 取得名稱
return name;
}
public void print(String string) { // 輸出名稱
System.out.println("=== " + name + " ===");
System.out.println(string);
}
private void heavyJob(String msg) { // 較重的工作(假設)
System.out.print(msg);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.print(".");
}
System.out.println("完成。");
}
}
代理類:真正要打印了才去調用生成printer并且參數賦值進行打印操作
public class PrinterProxy implements Printable {
private String name; // 名稱
private Printable real; // 「本人」
private String className; // 「本人」的類名稱
public PrinterProxy(String name, String className) { // 構造子
this.name = name;
this.className = className;
}
public synchronized void setPrinterName(String name) { // 命名
if (real != null) {
real.setPrinterName(name); //「本人」也要命名
}
this.name = name;
}
public String getPrinterName() { // 取得名稱
return name;
}
public void print(String string) { // 輸出到畫面上
realize();
real.print(string);
}
private synchronized void realize() { // 產生「本人」
if (real == null) {
try {
real = (Printable) Class.forName("Proxy." + className)
.newInstance();
real.setPrinterName(name);
} catch (ClassNotFoundException e) {
System.err.println("找不到類 " + className + "。");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
無論怎么調用setPrinterName方法都不會產生real實例 只有真正需要生成本人的時候才會生成
測試方法:
public class Main {
public static void main(String[] args) {
Printable p = new PrinterProxy("Alice", "Printer");
System.out.println("現在的名稱是" + p.getPrinterName() + "。");
p.setPrinterName("Bob");
//不會生成Printer
System.out.println("現在的名稱是" + p.getPrinterName() + "。");
//不會生成Printer
p.print("Hello, world.");
//生成Printer
}
}