.NET中的Entity Framework 和 java里面的 Hibernate都是ORM框架,它们中间都用到延时加载,延时加载对于提高性能,减小服务器内存压力有很大的作用。所谓延时加载,就是只有在第一次调用某个实体的方法或属性时才初始化该实体。延时加载适用于创建开销大的对象。如下,我采用代理模式模拟了一个简单的延时加载的例子。
首先,我定义了一个接口,名为IOperation,定义如下:
1 public interface IOperation 2 { 3 /// <summary> 4 /// 声明一个描述类信息的方法,由子类实现。 5 /// </summary> 6 void Describe(); 7 /// <summary> 8 /// 声明一个销毁订单的操作,由子类操作 9 /// </summary> 10 void DestoryOrder(); 11 }
然后定义两个实体类,Product类和Order类,分别表示两个相互关联的实体,在Product类中注入Order类的变量用以在Product类中调用Order类的实例方法。并且让Product类实现IOperate接口。
Product类定义如下:
1 public class Product : IOperation 2 { 3 private Order _order; 4 public Product() 5 { 6 Console.WriteLine(">>开始初始化Product类..."); 7 Stopwatch sw = new Stopwatch(); 8 sw.Start(); 9 this._order = new Order(); 10 sw.Stop(); 11 Console.WriteLine(">>初始化Product类完成。耗时:{0}秒", sw.ElapsedMilliseconds / 1000); 12 } 13 public void Describe() 14 { 15 Console.WriteLine(">>Product描述:我的是Product类的实例,Describe方法执行完成。"); 16 } 17 public void DestoryOrder() 18 { 19 Console.WriteLine(">>Product.DestoryOrder()方法开始执行..."); 20 if (_order != null) 21 { 22 //调用Order类的Destroy实例方法,销毁自己。 23 _order.Destroy(); 24 Console.WriteLine(">>Product.DestoryOrder()方法执行完成。"); 25 } 26 } 27 }
Order类定义如下:
1 public class Order 2 { 3 public Order() 4 { 5 Console.WriteLine(">>开始初始化Order类..."); 6 System.Threading.Thread.Sleep(5000); 7 Console.WriteLine(">>初始化Order类完成。"); 8 } 9 10 public void Destroy() 11 { 12 Console.WriteLine(">> Order 已销毁。"); 13 } 14 }
然后在主程序里面调用一下:
1 static void Main(string[] args) 2 { 3 Console.WriteLine("==========不使用代理类调用Describe()方法==============="); 4 Product p = new Product(); 5 p.Describe(); 6 Console.WriteLine("==========不使用代理类调用DestoryOrder()方法==============="); 7 Product p2 = new Product(); 8 p2.DestoryOrder(); 9 Console.ReadKey(); 10 }
>
测试结果如下:
从上图中,我们可以看出,调用Describe()方法初始化Product类用了5秒,这是不是有问题?再看看上面的Describe()方法的实现,只简单的输出了一句话,怎么会用5秒?再看Product的构造函数里面,在初始化Product类的实例的时候,把Order类也初始化了,但是我这个Describe()方法并没有调用Order类的任何方法和属性,所以这就造成了不必要的内存开销,而且初始化了的Order类的实例也没有使用,产生了垃圾对象。
怎么解决这个问题呢?所以这个地方就得用代理了,代理是个什么东西呢?代理简单来说,就是制造一个与被调对象具有相同功能(这个相同功能通常由接口去规范)的类,在这个类中可以调用被调对象的方法,也可以自定义新的方法供调用方使用。下面就是代理类的创建。
首先,我创建一个代理类,名为ProxyProduct,让它也实现IOperate接口,定义如下:
1public class ProxyProduct : IOperation 2{ 3 private IOperation entity; 4 5 public ProxyProduct(IOperation entity) 6 { 7 Console.WriteLine(">>开始初始化ProxyProduct..."); 8 Stopwatch sw = new Stopwatch(); 9 sw.Start(); 10 this.entity = entity; 11 sw.Stop(); 12 Console.WriteLine(">>初始化ProxyProduct完成。耗时:{0}秒", sw.ElapsedMilliseconds / 1000); 13 } 14 /// <summary> 15 /// 实现IOperation的方法 16 /// </summary> 17 public void Describe() 18 { 19 Console.WriteLine(">>ProxyProduct描述:我的是ProxyProduct类的实例,Describe()方法执行完成。"); 20 } 21 /// <summary> 22 /// 实现IOperation的方法 23 /// </summary> 24 public void DestoryOrder() 25 { 26 Console.WriteLine(">>ProxyProduct.DestoryOrder()方法开始执行..."); 27 if (entity == null) 28 { 29 entity = new Product(); 30 } 31 entity.DestoryOrder(); 32 Console.WriteLine(">>ProxyProduct.DestoryOrder()方法执行完成。"); 33 } 34}
在主程序里面测试一下:
1 static void Main(string[] args) 2 { 3 Console.WriteLine("==========使用代理类调用Describe()方法==============="); 4 IOperation desc = new ProxyProduct(null) as IOperation; 5 if (desc != null) 6 { 7 desc.Describe(); 8 } 9 Console.WriteLine("==========使用代理类调用DestoryOrder()方法==============="); 10 IOperation desc2 = new ProxyProduct(null) as IOperation; 11 if (desc2 != null) 12 { 13 desc2.DestoryOrder(); 14 } 15 Console.ReadKey(); 16 }
测试结果如下:
从上图看出,调用Describe()方法时耗时0秒,调用DestoryOrder()方法时,初始化代理类用了0秒,初始化Product类用了5秒,所以执行DestroyOrder()方法一共花费了5秒。这样的结果是令人满意的,使用代理类就实现了“调用谁的方法,就初始化谁;不调用不初始化”的想法。这样的话,如果我永远只调Describe()方法,那么我花费的时间永远是0秒,而不会产生额外的开销,这对性能优化有很大的帮助。
总结:代理模式应用之一:对于某些创建时需要很大开销的对象,我们可以使用代理让这个对象在第一次调用它的方法或属性时才创建它的实例,不调用它的方法或属性则永远不创建它的实例。好处:性能优化,减小内存开销。
==================================================================================================================
如下是java代码实现:
接口:IOperate
1 public interface IOperate { 2 /** 3 * 声明一个描述类信息的方法,由子类实现。 4 */ 5 void describe(); 6 /** 7 * 声明一个销毁订单的方法,由子类实现。 8 */ 9 void destroyOrder(); 10 }
实现类:ProductBean
1 public class ProductBean implements IOperate { 2 private OrdersBean ordersBean; 3 4 /** 5 * 初始化ProductBean类的实例 6 */ 7 public ProductBean() { 8 System.out.println(">>开始初始化ProductBean...."); 9 long startTime = System.currentTimeMillis(); 10 this.ordersBean = new OrdersBean(); 11 long endTime = System.currentTimeMillis(); 12 System.out.println(">>初始化ProductBean完成。耗时:" + (endTime - startTime) / 1000 + "秒"); 13 } 14 15 public void describe() { 16 System.out.println(">>describe描述:我是ProductBean类,执行了describe()方法。"); 17 } 18 19 public void destroyOrder() { 20 System.out.println(">>开始执行ProductBean.destroyOrder()方法..."); 21 if (this.ordersBean != null) { 22 this.ordersBean.destroy(); 23 System.out.println(">>ProductBean.destroyOrder()方法执行完成。"); 24 } 25 } 26 }
实体类:OrderBean
1 public class OrdersBean { 2 public OrdersBean() { 3 System.out.println(">>开始初始化OrderBean....."); 4 InitOrder(); 5 System.out.println(">>初始化OrderBean完成。"); 6 } 7 8 /** 9 * 初始化订单 10 */ 11 private void InitOrder() { 12 try { 13 // 加载订单数据,这里模拟耗时3秒。 14 Thread.sleep(5000); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 20 public void destroy() { 21 System.out.println(">> Order 已销毁。"); 22 } 23 }
代理类:ProxyProductBean
1 public class ProxyProductBean implements IOperate { 2 private IOperate bean; 3 4 public ProxyProductBean(IOperate bean) { 5 System.out.println(">>开始初始化ProxyProductBean....."); 6 long startTime = System.currentTimeMillis(); 7 this.bean = bean; 8 long endTime = System.currentTimeMillis(); 9 System.out.println(">>初始化ProxyProductBean完成。耗时:" + (endTime - startTime) / 1000 + "秒"); 10 } 11 12 public void describe() { 13 System.out.println(">>describe描述:我是ProxyProductBean类,执行了describe()方法。"); 14 } 15 16 public void destroyOrder() { 17 System.out.println(">>开始执行ProxyProductBean.destroyOrder()方法..."); 18 if (bean == null) { 19 bean = new ProductBean(); 20 bean.destroyOrder(); 21 System.out.println(">>执行ProxyProductBean.destroyOrder()方法完成。"); 22 } 23 } 24 }
测试类:
1 public class Test { 2 public static void main(String[] args) { 3 System.out.println("==========不使用代理类调用describe()方法==============="); 4 ProductBean productBean = new ProductBean(); 5 productBean.describe(); 6 System.out.println("==========使用代理类调用describe()方法==============="); 7 IOperate description = (IOperate) (new ProxyProductBean(null)); 8 description.describe(); 9 System.out.println("==========不使用代理类调用cascadeOperate()方法==============="); 10 ProductBean productBean2 = new ProductBean(); 11 productBean2.destroyOrder(); 12 System.out.println("==========使用代理类调用cascadeOperate()方法==============="); 13 IOperate description2 = (IOperate) (new ProxyProductBean(null)); 14 description2.destroyOrder(); 15 } 16 }
测试结果输出如下:
==========不使用代理类调用describe()方法===============
>>开始初始化ProductBean....
>>开始初始化OrderBean.....
>>初始化OrderBean完成。
>>初始化ProductBean完成。耗时:5秒
>>describe描述:我是ProductBean类,执行了describe()方法。
==========使用代理类调用describe()方法===============
>>开始初始化ProxyProductBean.....
>>初始化ProxyProductBean完成。耗时:0秒
>>describe描述:我是ProxyProductBean类,执行了describe()方法。
==========不使用代理类调用cascadeOperate()方法===============
>>开始初始化ProductBean....
>>开始初始化OrderBean.....
>>初始化OrderBean完成。
>>初始化ProductBean完成。耗时:5秒
>>开始执行ProductBean.destroyOrder()方法...
>> Order 已销毁。
>>ProductBean.destroyOrder()方法执行完成。
==========使用代理类调用cascadeOperate()方法===============
>>开始初始化ProxyProductBean.....
>>初始化ProxyProductBean完成。耗时:0秒
>>开始执行ProxyProductBean.destroyOrder()方法...
>>开始初始化ProductBean....
>>开始初始化OrderBean.....