代理(Proxy)模式是创建一个类型为其他对象提供一种代理以控制对这个对象的访问。
代理模式有以下几种常见的应用:
1、远程代理(Remote Proxy)为一个其他的地址空间里的对象提供一个本地代表,这样可以隐藏一个对象存在于不同地址空间的事实。
2、虚代理(Virtual Proxy)为一个创建开销很大的对象提供代理,在需要创建的时候再延迟创建。
3、保护代理(Protection Proxy)控制对原始对象的访问。
4、智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作:
(1)增加引用计数(当引用计数为零时,自动释放该对象)
(2)当第一次引用一个持久对象时,将它装入内存。
(3)当访问一个实际对象前,检查它是否已经被锁定,用以确保它不能被其他对象改变。
虚代理的示例,延迟加载图片:
namespace TestProxy
{
public interface IImage
{
void Draw();
}
public class Image : IImage
{
public Image(string fileName)
{
//TODO:
Console.WriteLine("Loading image");
}
public void Draw()
{
//TODO:
Console.WriteLine("Drawing image");
}
}
public class ImageProxy : IImage
{
private Image _realImage = null;
private string _filePath;
public ImageProxy(string filePath)
{
_filePath = filePath;
}
protected Image GetImage ()
{
if (null == _realImage) {
_realImage = new Image (_filePath);
}
return _realImage;
}
public void Draw()
{
GetImage().Draw ();
}
}
}
使用ImageProxy包装Image,只在调用Draw方法的时候,才会创建图片的真正对象。保护代理的示例,有一个Hero对象,公开了attack和maxHP的属性,可读可写:
public interface IHero
{
int attack { get; set;}
int maxHP { get; set;}
}
public class Hero:IHero
{
public int attack{get;set;}
public int maxHP{get;set;}
}
但是我们希望attack和maxHP是只读的,但是有些时候我们可能并不方便修改Hero的代码,那么我们就可以为Hero添加一个代理:
public class HeroProxy:IHero
{
private Hero _realHero;
public HeroProxy()
{
_realHero = new Hero();
InitializeHeroData();
}
private void InitializeHeroData()
{
//TEST
_realHero.attack = 10;
_realHero.maxHP = 100;
}
public int attack{
get
{
return _realHero.attack;
}
set
{
throw new System.Exception("Hero's attack is readonly!");
}
}
public int maxHP{
get
{
return _realHero.maxHP;
}
set
{
throw new System.Exception("Hero's attack is readonly!");
}
}
}
使用:
HeroProxy hero = new HeroProxy ();
try
{
hero.attack = 255;
}
catch (System.Exception e)
{
Console.WriteLine(e);
}
运行时,我们就可以catch到异常。
代理模式的优点:隐藏了访问某个对象的细节和复杂性,并且可以为对象添加一些额外的操作。
缺点:额外增加了一个对象,这也就意味着内存消耗会增加,并且因为是间接处理,所以处理速度也会下降。当然,这也增加系统的复杂度。