跳到主要内容

13、C#设计模式 - 代理模式

代理模式(Proxy Pattern)

代理模式属于结构型模式,为其他对象提供一种代理以控制对这个对象的访问。

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

角色:

1、 抽象主题(Subject);

通过接口或抽象类声明真实角色实现的业务方法;

2、 代理主题(Proxy);

真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作;

3、 真实主题(RealSubject);

定义真实角色所要实现的业务逻辑,供代理角色调用。

示例:

 

命名空间ProxyPattern中包含Employee员工类充当抽象主题,Leader领导类充当代理主题,Staff普通员工类充当真实主题。本案例尝试通过员工采购一批桌子来介绍领导是如何通过使用普通员工作为自己的代理为公司采购商品的。

namespace ProxyPattern
public abstract class Employee {

	public abstract void Purchase(string goods);

	protected virtual void OnPurchasing() {
		Console.WriteLine("Employee.OnPurchasing()");
	}

	protected virtual void OnPurchased() {
		Console.WriteLine("Employee.OnPurchased()");
	}

}

员工类Employee。

public class Staff : Employee {

	public override void Purchase(string goods) {
		OnPurchasing();
		Console.WriteLine($"Purchase some {goods}s!");
		OnPurchased();
	}

	protected override void OnPurchasing() {
		Console.WriteLine("Staff.OnPurchasing()");
	}

	protected override void OnPurchased() {
		Console.WriteLine("Staff.OnPurchasing()");
	}

}

普通员工类Staff。

public class Leader : Employee {

	private Staff _staff = null;

	public Leader() {
		_staff = new Staff();
	}

	public override void Purchase(string goods) {
		_staff.Purchase(goods);
	}

}

领导类Leader,内部维持一个员工的引用,并在Purchase采购方法调用普通员工的采购方法。完成了一次代理购物。

public class Program {

	private static Employee _employee = null;

	public static void Main(string[] args) {
		_employee = new Leader();
		_employee.Purchase("desk");

		Console.ReadKey();
	}

}

以上是调用方的代码,以下是这个案例的输出结果:

Staff.OnPurchasing()
Purchase some desks!
Staff.OnPurchasing()

优点:

1、 代理模式能够将调用用于真正被调用的对象隔离,在一定程度上降低了系统的耦合度;
2、 代理对象在客户端和目标对象之间起到一个中介的作用,这样可以起到对目标对象的保护;
3、 代理对象可以在对目标对象发出请求之前进行一个额外的操作,例如权限检查等;

缺点:

1、 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢;
2、 实现代理模式需要额外的工作,从而增加了系统的实现复杂度;

使用场景:

1、 当客户端对象需要访问远程主机中的对象时可以使用远程代理;
2、 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理,例如一个对象需要很长时间才能完成加载时;
3、 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理通过使用缓冲代理,系统无须在客户端每一次访问时都重新执行操作,只需直接从临时缓冲区获取操作结果即可;
4、 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理;
5、 当需要为一个对象的访问(引用)提供一些额外的操作时可以使用智能引用代理;