代理模式 - 真正的主题不是从客户端隐藏的

时间:2013-11-28 21:04:49

标签: design-patterns proxy-pattern

我正在阅读DoFactoryWikipedia上的代理,以及Stack Overflow。 一切都很清楚,Real Subject除外。在DoFactory上,Proxy定义为:

  

为另一个对象提供代理或占位符以控制对其的访问。   (加粗字体)

如果其目的是控制对Real Subject的访问权限,为什么Real Subject未隐藏Client

这是代理的UML图:

Proxy UML

在代码示例中,Real Subject定义为:

class RealSubject : Subject
{
    ...
}

客户通过它创建Proxy的实例并“控制对Real Subject的访问权”:

Proxy proxy = new Proxy();
proxy.Request();

但是(从我看到的几个例子中)没有什么可以阻止客户端实例化Real Subject并访问其方法。我想知道为什么会这样?

2 个答案:

答案 0 :(得分:1)

您当然可以实现代理模式,以便RealSubject对客户端不可见。实际上,如果每个客户都希望只使用代理,那将是一个很好的OO方法。

另一方面,代理通常用于提高效率或安全性,或添加延迟加载等功能。如果有许多客户端,其中一些可能不需要代理添加的客户端,并将直接使用RealSubject。

对于库API,可能会暴露(公共)RealSubject以允许任何客户端实现自己的代理。然后,即使客户端仅使用其代理,RealSubject也会对客户端可见。

另一种情况是Proxy可能只提供RealSubject的部分接口。以控制对RealSubject访问的保护代理为例。对客户端进行身份验证后,可以允许直接访问RealSubject,并且可以处理代理。

如您所见,代理的价值通常取决于所涉及的客户。有些客户可能只使用它,在这种情况下可以隐藏RealSubject。其他客户可能暂时使用它,而其他客户可能根本不使用它。

答案 1 :(得分:1)

我会给你一个例子,我想这将帮助你获得代理的目的/力量,并尝试显示控制对象访问的含义。

假设我有一个实现给定接口DataStore的对象(或实体)的商店IModel

我的合同如下:

public interface IDataStore(){

   // Return a given model by its id
   public IModel getModelById(Long ID);

   // Return the set of models that were modified by DataStore Clients.
   public Collection<IModel> getModifiedModels();
}

第二种方法合同有点复杂,解决起来很麻烦。 (复杂的)解决方案是保留返回的每个IModel的副本,然后在原始元素之间进行比较。 使用代理模式,我们的DataStore可以以一种优雅的方式履行他的合同:当查询具有给定id的模型时,他实际上将向您返回一个代理,该代理通知任何修改的数据存储。

为了便于说明,以下是对合同的解释:

// The following is equivalent to "Subject" using your nomenclature
public interface IModel{

   public Long getId()
   public void setId(Long id);
}

// The following is equivalent to the "RealSubject"
public class RealModel implements IModel{

   Long id;
   public void getId(){
      return id;
   }
   public void setId(Long newid){
      this.id = newid;
   }
}

最后这是我们的代理人:

public class ModelProxy extends RealModel implements IModel{

   IModel proxiedModel;
   DataStore datastore;//our datastore

   public ModelProxy(IModel model, DataStore ds){
       proxiedModel=model;
       datastore = ds;
   }

   public void setId(Long newid){

      datastore.addModified(this);
      //  (Assume the DataStore implementation has the addModified method)
      //  The more important here is that we are really "controlling access" to 
      //  our model : before allowing client to modify the id, we're
      //  notifying the store of the modification, and the client hasn't to know about 
      //  that as he's only aware of the IModel interface contract.
      this.id = newid;


   }

}