定义

为其他对象提供一种代理以控制对这个对象的访问。

代理模式也叫做委托模式,它是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。

代理类负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

基本上可以理解为:代理类持有实际操作对象的引用,通过公开方法将这些引用的方法提供给其它类调用。

和其它模式的区别

  1. 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理迷失不能改变所代理类的接口。
  2. 和装饰模式的区别:装饰模式为了增强功能,而代理模式是为了加以控制。

UML

优点

  1. 真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
  2. 具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

缺点

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

应用场景

远程代理

为一个对象在不同的地址空间提供局部代表。

虚代理

根据需要创建开销很大的对象。比如浏览网页时,图片可以使用代理先按宽高进行占位,下载好再进行显示。

保护代理

控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。

智能指针

取代了简单的指针,它在访问对象时执行一些附加操作。

它的典型用途包括:

  1. 对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它。
  2. 当第一次引用一个持久对象时,将它装入内存。
  3. 在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

示例

游戏玩家(被代练对象)和游戏代练者(代理对象)的示例,其中如果游戏玩家升级则游戏代练则要进行收费。

C++

C#

 using System;

 namespace DesignPattern
{
class Program
{
static void Main(string[] args)
{
//李雷自己打游戏
GamePlayer liLei = new GamePlayer("李雷");
liLei.Login();
liLei.KillMonster();
liLei.Upgrade(); Console.WriteLine(); //李雷花钱请游戏代练帮其升级
Leveling leveling = new Leveling(liLei);
leveling.Login();
leveling.KillMonster();
leveling.Upgrade(); Console.Read();
}
} /// <summary>
/// 游戏玩家接口.
/// </summary>
public interface IGamePlayer
{
/// <summary>
/// 登录.
/// </summary>
void Login(); /// <summary>
/// 打怪.
/// </summary>
void KillMonster(); /// <summary>
/// 升级.
/// </summary>
void Upgrade();
} /// <summary>
/// 玩家类.
/// </summary>
public class GamePlayer : IGamePlayer
{
private string _name; public GamePlayer(string name)
{
_name = name;
} public void Login()
{
Console.WriteLine("玩家\"" + _name + "\"登录游戏。");
} public void KillMonster()
{
Console.WriteLine("玩家\"" + _name + "\"开始打怪。");
} public void Upgrade()
{
Console.WriteLine("玩家\"" + _name + "\"等级提升一级。");
}
} /// <summary>
/// 游戏代练类.
/// </summary>
public class Leveling : IGamePlayer
{
private GamePlayer _gamePlayer; public Leveling(GamePlayer gamePlayer)
{
_gamePlayer = gamePlayer;
} public void Login()
{
_gamePlayer.Login();
} public void KillMonster()
{
_gamePlayer.KillMonster();
} public void Upgrade()
{
_gamePlayer.Upgrade(); Console.WriteLine("游戏代练者收费。");
}
}
}

Java

Java的示例使用延迟代理和动态代理查询天气的例子。

 public class Main
{
public static void main(String[] args)
{
//不使用代理
IWeather weather1 = new ChinaWeather();
System.out.println(weather1.getWeatherByCity("上海")); //延迟代理
IWeather weather2 = new ChinaWeatherDelayProxy();
System.out.println(weather2.getWeatherByCity("北京")); //动态代理
IWeather weather3 = new WeatherDynamicProxy(new InternationalWeather());
System.out.println(weather3.getWeatherByCity("北京"));
} /**
* 天气查询接口
*/
public interface IWeather
{
/**
* 获取指定城市的天气情况
*/
String getWeatherByCity(String city); /**
* 请求查询
*/
void request();
} /**
* 使用中国的天气服务器查询天气情况,只能查询到中国的天气
*/
public static class ChinaWeather implements IWeather
{
public ChinaWeather()
{
this.request();
} @Override
public String getWeatherByCity(String city)
{
if(city.equals("北京"))
{
return "晴 28度 PM2.5 20";
}
if(city.equals("上海"))
{
return "晴 33度 PM2.5 10";
}
return "未知";
} @Override
public void request()
{
System.out.println("请求中国的天气服务器,解析其格式得到信息");
}
} /**
* 使用国际的天气服务器查询天气情况,当然也可以查询到中国的天气了
*/
public static class InternationalWeather implements IWeather
{
public InternationalWeather()
{
this.request();
} @Override
public String getWeatherByCity(String city)
{
if(city.equals("北京"))
{
return "晴 29度 PM2.5 500+";
}
if(city.equals("上海"))
{
return "晴 32度 PM2.5 500+";
}
return "未知";
} @Override
public void request()
{
System.out.println("请求国际的天气服务器,解析其格式得到信息");
}
} /**
* 延迟代理
*/
public static class ChinaWeatherDelayProxy implements IWeather
{
private IWeather weather; private IWeather getWeather()
{
if(weather == null)
{
weather = new ChinaWeather();
}
return weather;
} @Override
public String getWeatherByCity(String city)
{
return getWeather().getWeatherByCity(city);
} @Override
public void request()
{
getWeather().request();
}
} /**
* 动态代理
*/
public static class WeatherDynamicProxy implements IWeather
{
private IWeather weather; public WeatherDynamicProxy(IWeather weather)
{
this.weather = weather;
} @Override
public String getWeatherByCity(String city)
{
return weather.getWeatherByCity(city);
} @Override
public void request()
{
weather.request();
}
}
}

AS3

我的经验总结

在PureMVC框架中,其Model层使用了Proxy的设计模式。

我们先看看Model层的主要功能:

  1. 保存程序数据;
  2. 远程消息发送及请求。

在我们的游戏中,分别存在UserData及SocketConnection这两个对象,其中UserData用来存储用户数据,SocketConnection用来处理所有远程消息的接收和发送,而每个模块的Proxy都是对这两个对象的代理,其提供该模块需要的数据和操作接口给该模块,比如技能模块中,Proxy会提供技能相关的数据和协议给到该模块的View层。代理类为模块提供了屏蔽不需要的接口的功能。

然而在PureMVC的升级版框架RobotLegs中,其定义的是MVCS的框架,Model层直接设计为Model+Services的组合,没有使用代理模式,由于没有代理模式,所以中介类中就不是直接操作代理类,而一般情况是通过发送Command,在Command中进行处理。

结构类模式(七):代理(Proxy)的更多相关文章

  1. 设计模式之结构类模式大PK

                                      结构类模式大PK 结构类模式包括适配器模式.桥梁模式.组合模式.装饰模式.门面模式.享元模式和代理模式.之所以称其为结构类模式,是因 ...

  2. 设计模式之结构类模式PK

    结构类模式包括: 适配器模式 桥梁模式 组合模式 装饰模式 门面模式 享元模式 代理模式 结构类模式着重于如何建立一个软件结构 为什么叫结构类模式呢? 因为他们都是通过组合类或对象产生更大结构以适应更 ...

  3. 结构型模式(七) 代理模式(Proxy)

    一.动机(Motivate) 在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者.或者系统结构带来很多麻烦.如何在不 ...

  4. 结构类模式(四):装饰(Decorator)

    定义 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 特点 装饰对象和真实对象有相同的接口.这样客户端对象就能以 ...

  5. 结构类模式(三):组合(Composite)

    定义 将对象组合成树形结构以表示“部分整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客 ...

  6. 结构类模式(六):享元(Flyweight)

    定义 运用共享技术有效的支持大量细粒度的对象. 两个状态 内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的. 外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保 ...

  7. 结构类模式(五):外观(Facade)

    定义 为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用. UML 优点 对客户屏蔽了其子系统组件,因而减少了客户处理对象的数目,并使得子系统实用起来更方便. ...

  8. 结构类模式(二):桥接(Bridge)

    定义 将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化. 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维 ...

  9. 结构类模式(一):适配器(Adapter)

    定义 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 类适配器模式 使用继承的方式实现没有提供的接口从而达到适配到新系统的需求. ...

随机推荐

  1. Python 删除 数组

    numpy删除一列 从0开始,第三个参数是第几个维度  可以多删几个 

  2. mysqldump备份数据库时排除某些库

    说明:使用mysqldump –all-databases会导出所有库.但如果做主从,从主库dump出数据时,我们是不需要也不想要information_schema 和 mysql 库的.数据库少的 ...

  3. 三 最简单的 AndEngine 程序框架

    package com.example.AndEngineExample; import org.anddev.andengine.engine.Engine;import org.anddev.an ...

  4. NoSQL--非关系型的数据库是什么?

    NoSQL,指的是非关系型的数据库.NoSQL,意即反SQL运动,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨.NoSQL的拥护者们提倡运用非关系型的数据存储,相对于目前 ...

  5. linux 下按在sqllite

    1 安装 去sqlite主页http://www.sqlite.org/.跳转到下载也http://www.sqlite.org/download.html.源码下载sqlite-amalgamati ...

  6. php获取网站根目录

    php获取网站根目录方法一:<?phpdefine("WWWROOT",str_ireplace(str_replace("/","\\&quo ...

  7. HTTP协议学习笔记-1

    基本概念 首先需要了解几个概念: WEB客户端和服务器: WEB客户端当然就是指我们用使用的某个网站 服务器就是WEB资源源头,我们从服务器去请求数据,服务器把请求的数据发给WEB客户端 媒体类型: ...

  8. IOS中UIScrollView的详细使用

    UIScrollView 是可以滚动的View 要想让UIScrollView可以滚动,必须设置UIScrollView的contentSize contentSize : 表示UIScrollVie ...

  9. CentOS下安装gns3

    1.安装支持环境 sudo yum intall PyQt4 telnet 2.安装抓包用的wireshark sudo yum install wireshark wireshark-gnome 3 ...

  10. jQuery文档加载完毕的几种写法

    js中文档加载完毕.一般在body加一个onload事件或者window.onload = function () {} jQuery中有好多写法,平时也不注意,别人一问,还真觉得头大. 下面是我整理 ...