您的位置:首页 > 编程语言 > Java开发

《Java设计模式》之代理模式

2015-08-17 14:20 621 查看
1,什么是代理模式?

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。



2,策略模式有什么好处?

在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。



3,代理模式一般涉及到的角色有:



抽象角色:声明真实对象和代理对象的共同接口;

代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。





4,应用场景举例:



比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时是这样的体现的

先说说这个场景中的要素:一种类型的女人,潘金莲,王婆,西门庆,后来扩展的贾氏也和西门庆勾上了,我们是假设的,然后西门庆找潘金莲happy,但潘金莲不好意思直接,就找个王婆代理呗。我们看看具体代码。



先定义一种女人

package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *定义一种类型的女人,王婆和潘金莲都属于这个类型的女人
 */
public interface KindWoman {
	
	//这种女人能做什么事情呢?
	public void makeEyesWithMan();//抛媚眼
	
	public void happyWithMan();//和男人那个....

}


一种类型嘛,那肯定是接口,定义个潘金莲

package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *定义一个潘金莲是什么样的人
 */
public class PanJinLian  implements KindWoman{

	@Override
	public void happyWithMan() {
		System.out.println("潘金莲和男人在做那个...");
		
	}

	@Override
	public void makeEyesWithMan() {
		System.out.println("潘金莲抛媚眼...");
		
	}

}


再定义个丑陋的王婆
package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *王婆这个人老聪明了,她太老了,是个男人都看不上她,
 *但是她有智慧经验呀,他作为一类女人的代理!
 */
public class WangPo implements KindWoman {
	
	private KindWoman kindWoman;
	
	public WangPo(){
		//默认的话是潘金莲的代理
		this.kindWoman = new PanJinLian();
	}
	//她可以是KindWomam的任何一个女人的代理,只要你是这一类型
	public WangPo(KindWoman kindWoman){
		this.kindWoman = kindWoman;
	}

	@Override
	public void happyWithMan() {
		//自己老了,干不了了,但可以叫年轻的代替。
		this.kindWoman.happyWithMan();
		
	}

	@Override
	public void makeEyesWithMan() {
		//王婆年纪大了,谁看她抛媚眼啊
		this.kindWoman.makeEyesWithMan();
		
	}

}


两个女主角都上场了,该男主角了,定义个西门庆
package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下:
 *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很!
 */
public class XiMenQiang {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		WangPo wangPo;
		//把王婆叫出来
		 wangPo = new WangPo();
		//然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏:
		wangPo.makeEyesWithMan();
		//看到没有表面是王婆在做,其实爽的是潘金莲
		wangPo.happyWithMan();
		
		

	}

}




那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去了王婆这个中间环节,直接西门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。

那我们再考虑一下,水浒里面还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个管家苟合的那个),这个名字起的:“贾氏”,那我们也让王婆做她的代理:

package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *定义一个贾氏是什么样的人
 */
public class JiaShi implements KindWoman {

	@Override
	public void happyWithMan() {
		System.out.println("贾氏和男人在做那个...");
		
	}

	@Override
	public void makeEyesWithMan() {
		System.out.println("贾氏抛媚眼...");
		
	}

}


西门庆勾潘金莲又勾引贾氏

package com.yangguangfu.proxy;
/**
 * 
 * @author 阿福(trygf521@126.com)<br>
 *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下:
 *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很!
 */
public class XiMenQiang {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		WangPo wangPo;
		//把王婆叫出来
		 wangPo = new WangPo();
		//然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏:
		wangPo.makeEyesWithMan();
		//看到没有表面是王婆在做,其实爽的是潘金莲
		wangPo.happyWithMan();
		
		
		
		//西门庆勾引贾氏
		JiaShi jiaShi = new JiaShi();
		wangPo = new WangPo(jiaShi);
		wangPo.makeEyesWithMan();
		wangPo.happyWithMan();

	}

}


说完这个故事,那我总结一下,代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口呗。好了不多说了,慢慢体会吧。

为了更好地理解,那就接着往下看吧!

为另一个对象提供一个替身或占位符以控制对这个对象的访问,简而言之就是用一个对象来代表另一个对象。

类图:



简单例子:有个接口Italk,people对象实现这个接口的talk()方法,有些想另外加入sing()方法,所以增加代理类talkProxy,实现两个方法.

public interface ITalk

{

public void talk(String msg);

}

public class People implements ITalk

{

@Override

public void talk(final String msg)

{

System.out.println(msg);

}

}

public class TalkProxy implements ITalk

{

ITalk italk;

public TalkProxy(final ITalk italk)

{

this.italk = italk;

}

@Override

public void talk(final String msg)

{

this.italk.talk(msg);

}

public void sing(final String songName)

{

System.out.println("Song Name:" + songName);

}

}

public class Client

{

public static void main(final String[] args)

{

final People people = new People();

people.talk("I can't sing");

final TalkProxy proxy = new TalkProxy(people);

proxy.talk("I can talk");

proxy.sing("I can sing");

}

}

结果:

I can't sing

I can talk

Song Name:I can sing

常见的代理:

1. 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也

可是在另一台主机中,远程代理又叫做大使(Ambassador)。

import java.rmi.Remote;

import java.rmi.RemoteException;

public interface MyRemote extends Remote

{

public String getUserName(String userId) throws RemoteException;

}

import java.rmi.RemoteException;

import java.rmi.server.UnicastRemoteObject;

public class MyRemoteImp extends UnicastRemoteObject implements MyRemote

{

protected MyRemoteImp() throws RemoteException

{



}

public String getUserName(String userId) throws RemoteException

{

return userId + "/myName is Cherry";

}

}

在cmd中输入:

javac MyRemote.java

javac MyRemoteImp.java

rmic MyRemoteImp

生成类的class文件及MyRemoteImp_Stub.class文件

import java.net.MalformedURLException;

import java.rmi.Naming;

import java.rmi.RemoteException;

public class MyRemoteServer

{

public static void main(final String[] args)

{

// YTODO Auto-generated method stub

MyRemote remote;

try

{

remote = new MyRemoteImp();

Naming.rebind("RemoteService", remote);

}

catch (final RemoteException e)

{

// YTODO Auto-generated catch block

e.printStackTrace();

}

catch (final MalformedURLException e)

{

// YTODO Auto-generated catch block

e.printStackTrace();

}

}

}

import java.net.MalformedURLException;

import java.rmi.Naming;

import java.rmi.NotBoundException;

import java.rmi.RemoteException;

public class MyRemoteClient

{

public static void main(final String[] args)

{

try

{

final MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1/RemoteService");

final String name = service.getUserName("my id is 001");

System.out.println(name);

}

catch (final MalformedURLException e)

{

e.printStackTrace();

}

catch (final RemoteException e)

{

e.printStackTrace();

}

catch (final NotBoundException e)

{

e.printStackTrace();

}

}

}

在dos下运行rmiregistry, 这个命令是开启RMI注册服务, 开启以后我们的server程序才能调用rebing方法发布我们的类,然后运行server程序

.

javac MyRemoteServer.java

java MyRemoteServer

start rmiregistry

javac MyRemoteServer.java

java MyRemoteServer

再打开一个dos运行客户端代码

javac MyRemoteClient.java

java MyRemoteClient

输出:my id is 001/myName is Cherry

这里一共有三个dos窗口, 当执行start rmiregistry时,会弹出它的窗口,当执行java MyRemoteServer的服务器端窗口,执行java

MyRemoteClient的客户端窗口(这里的rmiregistry.exe的窗口需要一直打开,否则无法调用服务器端).

2. 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表

示,真实对象只会在需要时才会被真正创建。

public interface Image

{

public void show();

}

public class BigImage implements Image

{

public BigImage()

{

//Thread.sleep(3000);//for simulating to load the big images

System.out.println("create the big images");

}

@Override

public void show()

{

System.out.println("show the big images");

}

}

public class ImageProxy implements Image

{

Image image;

public ImageProxy()

{

}

public ImageProxy(final Image image)

{

this.image = image;

}

@Override

public void show()

{

if (this.image == null)

{

this.image = new BigImage();

}

this.image.show();

}

}

public class Client

{

public static void main(final String[] args)

{

System.out.println("big image:");

final Image bigImage = new BigImage();

bigImage.show();

System.out.println("image proxy:");

final Image imageProxy = new ImageProxy();

imageProxy.show();

}

}

结果:

create the big images

show the big images

image proxy:

create the big images

show the big images

3. Copy-on-Write代理: 虚拟代理的一种,把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。

4. 保护代理(Protection or Access Proxy):控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。

5. 智能指引(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作.

总结一下代理模式的应用形式

(1)远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

(2)虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。

(3)写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。

(4)保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限

(5)缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。

(6)防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。

(7)同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。

(8)智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

(9)复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。



本文借鉴:http://www.cn`logs.com/itTeacher/archive/2012/12/14/2818572.html http://yangguangfu.iteye.com/blog/815787 http://blog.csdn.net/jackiehff/article/details/8621517
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: