今天学习了代理模式。
- 定义
官方:
代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。
Proxy Pattern: Provide a surrogate or placeholder for another object to control access to it.
我的理解:
原来是直接调用一个类的方法或者接口
现在中间多了一个代理类,先调用代理类,再通过代理类里面调用原来真实的类。
- 结构
- 场景
有以下几种代理模式:
1、保护代理
2、智能引用代理
第一,第二种代理例子:
原有系统:直接调用查询服务接口
新需求:要验证用户是否登录成功(新)=》调用原有查询接口=》记录查询日志(新)
class Proxy : Subject { private RealSubject realSubject = new RealSubject(); //维持一个对真实主题对象的引用 public void PreRequest() { …... } public override void Request() { PreRequest(); realSubject.Request(); //调用真实主题对象的方法 PostRequest(); } public void PostRequest() { …… } }
3、远程代理(通过调用远程服务器实现业务)
4、缓冲代理(查询很大的数据时候,可以保存在缓存中,下次调用就直接去缓存)
public static class ProductDataProxy { private static readonly int productTimeout = int.Parse(ConfigurationManager.AppSettings ["ProductCacheDuration"]); private static readonly bool enableCaching = bool.Parse(ConfigurationManager. AppSettings["EnableCaching"]); public static IList GetProductsByCategory(string category) { Product product = new Product(); //如果缓存被禁用,则直接通过product对象来获取数据 if (!enableCaching) { return product.GetProductsByCategory(category); } string key = "product_by_category_" + category; //从缓存中获取数据 IList data = (IList )HttpRuntime.Cache[key]; //如果缓存中没有数据则执行如下代码 if (data == null) { data = product.GetProductsByCategory(category); //通过工厂创建AggregateCacheDependency对象 AggregateCacheDependency cd = DependencyFacade.GetProductDependency (); //将数据存储在缓存中,并添加必要的AggregateCacheDependency对象 HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(product Timeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null); } return data; } …… }
5、虚拟代理
书上解析:
对于一些占用系统资源较多或者加载时间较长的对象,可以给这些对象提供一个虚拟代理
在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建之后,虚拟代理将用户的请求转发给真实对象
使用一个“虚假”的代理对象来代表真实对象,通过代理对象来间接引用真实对象,可以在一定程度上提高系统的性能
例子:
CD封面:加载要好慢,那么先弄一个简单的出来,然后异步加载真实数据,并且呈现。
//实现Icon接口 public class ImageProxy implements Icon { ImageIcon imageIcon; URL imageURL; Thread retrievalThread; boolean retrieving = false; // 将图片的URL传入构造器中 public ImageProxy(URL url) { imageURL = url; } // 在图像加载完毕前,返回默认的宽和高 // 图像加载完毕后,装给iamgeIcon处理 public int getIconWidth() { if (imageIcon != null) { return imageIcon.getIconWidth(); } else { return 800; } } public int getIconHeight() { if (imageIcon != null) { return imageIcon.getIconHeight(); } else { return 600; } } // 当要在屏幕上绘制图像时,就调用此方法 public void paintIcon(final Component c, Graphics g, int x, int y) { // 如果已经有了icon,就画出 if (imageIcon != null) { imageIcon.paintIcon(c, g, x, y); } else { // 还没有icon时,就显示“加载中...”的消息 g.drawString("CD封面加载中,请稍后...", x + 300, y + 190); if (!retrieving) { retrieving = true; // 在这个线程中加载真正的icon图像。注意,加载图像和ImageIcon是同步(synchronous) // 也就是说,只有在加载完之后,ImageIcon构造器才会返回。这样,我们的程序会耗在这里 // 所以要把加载变成异步(asynchronous)的。 retrievalThread = new Thread(new Runnable() { public void run() { try { imageIcon = new ImageIcon(imageURL, "CD Cover"); c.repaint(); } catch (Exception e) { e.printStackTrace(); } } }); retrievalThread.start(); } } } }