我也设计模式——11.Proxy
这个模式用途很多,先看它的UML:
{
abstract public void Request();
}
public class RealSubject : Subject
{
public override void Request()
{
//Do Something
}
}
public class Proxy : Subject
{
private RealSubject realSubject;
public override void Request()
{
//关键是这句话
realSubject.Request();
}
}
Client端使用如下:
Subject subject = new Proxy();
subject.Request();
Proxy有以下用途:
1.远程代理 Remoting和WebService都是基于此技术,这里就不多说了。
2.虚代理 单元测试中的Mock技术,以及加载大图片/处理大对象时的等待过程
Mock技术:如果现在的RealSubject类的Request()方法还没写好,可以继承Subject基类生成Proxy,这是Proxy类的Request()方法这么写:
{
//从配置文件中读取是否出于测试状态
bool isTest = GetConfiguration("isText");
if (isTest)
{
//写一些期望的假操作
}
else
{
realSubject.Request();
}
}
加载大图片:
{
Image getImage();
}
public class LargeImage : Imager
{
public Image getImage()
{
return new Bitmap(@"BigImage.jpg"); ;
}
}
public class ProxyImage : Imager
{
private Timer tm;
private bool isReady;
private LargeImage largeImage;
public ProxyImage()
{
isReady = false;
tm = new Timer(
delegate
{
isReady = true;
tm.Dispose();
},
this, 10000, 0);
}
public Image getImage()
{
if (isReady)
{
return largeImage.getImage();
}
else
{
return new Bitmap("SmallImage.gif");
}
}
}
在Client端调用方法:
private void Form1_Load(object sender, EventArgs e)
{
imgProxy = new ProxyImage();
}
private void btnLoad_Click(object sender, EventArgs e)
{
//Pic为一个PictureBox控件
Pic.Image = imgProxy.getImage();
}
注意这句话:
tm = new Timer(
delegate
{
isReady = true;
tm.Dispose();
},
this, 10000, 0);
关键就是这句话,开始isReady为false,加载小图片。10秒钟后才将isReady设置为true,并使Timer失效,从而再次调用ProxyImage的getImage()方法,加载大图片。
3.保护代理 控制对原始对象的访问,如增加/去除权限
原有系统的方法GetDisCount(),只有Role=管理员时才可以调用。
{
private string role;
public string Role
{
get { return role; }
set { role = value; }
}
public Double GetDiscount()
{
if (role == "admin")
{
return 1000;
}
else
{
throw new Exception();
}
}
}
现在要直接使用这个方法,而跳过权限控制,可以从中派生出一个子类ProxyCompDiscount:
{
private CompDiscount c;
public ProxyCompDiscount()
{
c = new CompDiscount();
c.Role = "admin";
}
public new Double GetDiscount()
{
return c.GetDiscount();
}
}
以上是去除多余的权限,相当于短路操作。反之,也可以使用同样的方法,增加权限。
4.智能指引 在访问对象时执行一些附加的操作,如强制类型集
{
private string fieldName;
public Field(string fieldName)
{
this.fieldName = fieldName;
}
}
public class FieldCollection : CollectionBase
{
public int Add(Field field)
{
return InnerList.Add(field);
}
public Field Add(string fieldName)
{
Field field = new Field(fieldName);
Add(field);
return field;
}
public void Add(params string[] fields)
{
foreach (string field in fields)
{
Add(field);
}
}
public Field this[int index]
{
get
{
return (Field)InnerList[index];
}
}
public void Remove(Field field)
{
InnerList.Remove(field);
}
}
在Client端,Proxy模式不用知道被代理的对象;而Decorator模式需要知道被修饰的对象。这是二者的区别。