设计模式--代理模式

来源:互联网 发布:会计软件 免费 编辑:程序博客网 时间:2024/06/07 01:11

代理模式proxy

1、概述

 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象,你曾有过延迟创建对象的想法吗 ( ifelse就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法给普通用户,特别方法给管理员用户?以上两种需求都非常类似,并且都需要解决一个更大的问题:你如何提供一致的接口给某个对象让它可以改变其内部功能,或者是从来不存在的功能可以通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。即代理对象。它可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务

例子1:经典例子就是网络代理,你想访问facebook或者twitter,如何绕过GFW,找个代理网站。

例子2:可以调用远程代理处理一些操作如图:

 

例子3:可以调用计数代理和远程代理处理一些操作

在一个图书馆里,所有的馆藏内容可以分为四大类:杂志、书籍、录像带和DVD。设计一个计数代理和rmi(远程代理)来记录每天各类内容被借阅的次数。 

2、Proxy常见情况

1) 远程代理(Remote  Proxy为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)
2) 虚拟代理(Virtual Proxy根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。 
3) 保护代理(Protection Proxy控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4) 智能指引(Smart Reference取代了简单的指针,它在访问对象时执行一些附加操作。
5) Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

3、结构

UML图:

 

简单的结构示意图:

 

 


 

 

4、实现步骤

 利用图书馆的例子来说明一般代理模式的步骤(采用了计数代理):

(1)创建接口CountIF.java

public interface CountIF {

public void getCount(String string);

}

 

(2)创建实现接口的实体类Content.java

  public class Contentimplements CountIF {

public void getCount(String string) {

// TODO Auto-generated method stub

System.out.println("-----------");

 }

}

(3)当被请求时,使用 CountProxy.java来获取Content 类的对象。

import java.util.HashMap;

import java.util.Map;

public class CountProxy implements CountIF {

  Integer Magazine=0;//杂志

 Integer Book=1;

  Integer Video=2;

  Integer DVD=3;

  Map<String,Integer> map;

 Content content;

public CountProxy(Content content) {

super();

this.content = content;

map=new HashMap<String,Integer>();

map.put( "杂志",Magazine);

map.put("书籍", Book);

map.put("录像",Video );

map.put("DVD",DVD );

}

int[] counts = new int[4];

public void getCount(String string) {

// TODO Auto-generated method stub

if(content==null){

content=new Content();

}

content.getCount(string);

counts[map.get(string)]++;

System.out.println(string+"的类别被借了"+counts[map.get(string)]);

}

}

 

4)创建客户端Client,向 CountProxy对象提交请求

public class Client {

public static void main(String[] args){

CountIF proxy=new CountProxy(new Content());

proxy.getCount("书籍");

proxy.getCount("杂志");

proxy.getCount("书籍");

proxy.getCount("杂志");

}

}

 

以下利用计算器的例子来说明远程代理的设计步骤

(1)制作远程的接口。远程接口定义出可以让客户远程调用的方法。客户将它作为服务的类类型。stub和实际的服务都需要实现此接口。
要注意:所有的方法都必须跑出RemoteException。确定变量和返回值是属于原语(primitive)类型或者可序列化的类型(Serializable)。
2)制作远程的实现
这个是实际工作的类。为远程接口中定义的远程方法提供了真正的实现。需要实现上面定义的远程接口。
3)利用rmic产生stubskeleton
这就是客户和服务的辅助类。默认的在java5以后此步可以省去
4)启动RMI registry
可以在cmd或者shell利用rmiregistry
5)开始远程服务让服务对象开始运行。
一定要注意调用rebind方法前,一定要先启动rmiregistry服务。

 

计算器的加法

 

Calculator 接口

package lin;

import java.rmi.Remote;

public interface Calculatorextends Remote  

 {  

    public long add(long a,long b)   

        throws java.rmi.RemoteException;  

}  

 

CalculatorImpl 实现类

package lin;

import java.rmi.server.UnicastRemoteObject;

public class CalculatorImpl extends UnicastRemoteObjectimplements Calculator{   

//这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常  

    public CalculatorImpl()  throws java.rmi.RemoteException {}

    public long add(long a,long b) throws java.rmi.RemoteException {   

        return a + b;   

    }   

}  

 

CalculatorServer 服务端

 

package lin;

import java.rmi.Naming;

import java.rmi.registry.LocateRegistry;

public class CalculatorServer {  

public CalculatorServer() {  

try{

Calculator c = new CalculatorImpl();  

LocateRegistry.createRegistry(1009);

Naming.rebind("rmi://localhost:1009/CalculatorService",c);  

System.out.print("wait");

}catch (Exception e) {  

System.out.println("Trouble: " + e);  }  }  

public static void main(String args[]) {  

new CalculatorServer(); }

}

 

CalculatorClient客户端

 

package lin;

import java.net.MalformedURLException;

import java.rmi.Naming;

import java.rmi.NotBoundException;

import java.rmi.RemoteException;

public class CalculatorClient {   

  public static void main(String[] args) throws NotBoundException {  

        try {   

            Calculator c = (Calculator)  

             Naming.lookup("rmi://localhost:1009/CalculatorService");   

             System.out.println( c.add(4, 5));  

         } catch (MalformedURLException murle) {   

              System.out.println("MalformedURLException");   

        } catch (RemoteException re) {   

             System.out.println("RemoteException");   

        }

      }

  }

5、参考文章

http://blog.csdn.net/pipisky2006/article/details/7296592
http://blog.csdn.net/hguisu/article/details/7542143

 

 

 


0 0