使用代理模式模拟ORM实体的延时加载

作者:小菜 更新时间:2025-02-26 点击数:
简介:.NET中的Entity Framework 和 java里面的 Hibernate都是ORM框架,它们中间都用到延时加载,延时加载对于提高性能,减小服务器内存

【菜科解读】

.NET中的Entity Framework 和 java里面的 Hibernate都是ORM框架,它们中间都用到延时加载,延时加载对于提高性能,减小服务器内存压力有很大的作用。

所谓延时加载,就是只有在第一次调用某个实体的方法或属性时才初始化该实体。

延时加载适用于创建开销大的对象。

如下,我采用代理模式模拟了一个简单的延时加载的例子。

首先,我定义了一个接口,名为IOperation,定义如下:

1 public interface IOperation 3 /// 4 /// 声明一个描述类信息的方法,由子类实现。

5 /// 6 void Describe(); 7 /// 8 /// 声明一个销毁订单的操作,由子类操作 9 /// 10 void DestoryOrder();11 }

然后定义两个实体类,Product类和Order类,分别表示两个相互关联的实体,在Product类中注入Order类的变量用以在Product类中调用Order类的实例方法。

并且让Product类实现IOperate接口。

Product类定义如下:

1 public class Product : IOperation 3 private Order _order; 4 public Product() 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);13 public void Describe()15 Console.WriteLine(">>Product描述:我的是Product类的实例,Describe方法执行完成。

");17 public void DestoryOrder()19 Console.WriteLine(">>Product.DestoryOrder()方法开始执行...");20 if (_order != null)22 //调用Order类的Destroy实例方法,销毁自己。

23 _order.Destroy();24 Console.WriteLine(">>Product.DestoryOrder()方法执行完成。

");27 }

Order类定义如下:

1 public class Order 3 public Order() 5 Console.WriteLine(">>开始初始化Order类..."); 6 System.Threading.Thread.Sleep(5000); 7 Console.WriteLine(">>初始化Order类完成。

");10 public void Destroy()12 Console.WriteLine(">> Order 已销毁。

");14 }

然后在主程序里面调用一下:

1 static void Main(string[] args) 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 3 private IOperation entity; 5 public ProxyProduct(IOperation entity) 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);14 /// 15 /// 实现IOperation的方法16 /// 17 public void Describe()19 Console.WriteLine(">>ProxyProduct描述:我的是ProxyProduct类的实例,Describe()方法执行完成。

");21 /// 22 /// 实现IOperation的方法23 /// 24 public void DestoryOrder()26 Console.WriteLine(">>ProxyProduct.DestoryOrder()方法开始执行...");27 if (entity == null)29 entity = new Product();31 entity.DestoryOrder();32 Console.WriteLine(">>ProxyProduct.DestoryOrder()方法执行完成。

");34}

在主程序里面测试一下:

1 static void Main(string[] args) 3 Console.WriteLine("==========使用代理类调用Describe()方法==============="); 4 IOperation desc = new ProxyProduct(null) as IOperation; 5 if (desc != null) 7 desc.Describe(); 9 Console.WriteLine("==========使用代理类调用DestoryOrder()方法===============");10 IOperation desc2 = new ProxyProduct(null) as IOperation;11 if (desc2 != null)13 desc2.DestoryOrder();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; 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 + "秒");15 public void describe() {16 System.out.println(">>describe描述:我是ProductBean类,执行了describe()方法。

");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()方法执行完成。

");26 }

实体类:OrderBean

1 public class OrdersBean { 2 public OrdersBean() { 3 System.out.println(">>开始初始化OrderBean....."); 4 InitOrder(); 5 System.out.println(">>初始化OrderBean完成。

"); 8 /** 9 * 初始化订单10 */11 private void InitOrder() {12 try {13 // 加载订单数据,这里模拟耗时3秒。

14 Thread.sleep(5000);15 } catch (Exception e) {16 e.printStackTrace();20 public void destroy() {21 System.out.println(">> Order 已销毁。

");23 }

代理类:ProxyProductBean

1 public class ProxyProductBean implements IOperate { 2 private IOperate bean; 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 + "秒");12 public void describe() {13 System.out.println(">>describe描述:我是ProxyProductBean类,执行了describe()方法。

");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()方法完成。

");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();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.....

使用,代理,模式,模拟,ORM,实体,的,延时,加载,

河南许昌社保卡可以当银行卡使用吗

社保卡一年交多少钱2024?在河南许昌上班的职工社保卡每个月交多少钱?社保的缴费档次,分为60%~300%之间都是可以选择的,当然如果说你是工作单位的在职员工,那么就可以通过自己的工作单位来缴纳社保,但是具体的社保缴费档次,是根据你本人工资的实际收入来确定的。

接下来随新社通app小编一起了解具体详情吧。

一、河南许昌社保养老金的计算公式是什么?河南许昌职工社保卡交满15年拿多少?根据河南许昌退休养老金计算公式,人们的养老金肯定包括基础养老金和个人账户养老金两部分,部分参保时间较早、工作时间较长的职工会有过渡性养老金这一待遇。

河南许昌基础养老金计算公式=河南许昌最新的养老金计发基数(1+本人平均缴费指数)÷2缴费年限1%。

河南许昌个人账户养老金计算公式=退休时养老保险个人账户的余额÷退休年龄确定的计发月数。

河南许昌过渡性养老金计算公式,是每一个省份都不一样,是根据当地省份的情况来制定的。

影响河南许昌养老金高低的五大因素。

根据上面所说的养老金计算公式情况,影响养老金高低的五大因素主要是退休地所在的养老金计发基数、缴费年限、本人的平均缴费指数、养老保险个人账户余额、退休年龄确定的计发月数。

由于过渡性养老金并不是所有人都有,所以就不单独说了。

①退休地所在的养老金计发基数,各地说实话相差还是比较大的。

②缴费年限,是包括实际缴费年限和视同缴费年限,这是计算养老金的一项极其重要因素。

其他因素都相同的情况下,养老金是跟缴费年限成正比的。

比如说缴费15年可以领取1500元的情况下,缴费30年可以领取3000元,缴费40年可以领取4000元。

③本人的平均缴费指数,主要是根据缴费基数和计算平均缴费指数使用的社平工资来计算的。

类似于缴费档次,一般在0.6~3之间。

平均缴费指数越高,计算出来的基础养老金就越高。

但是,不要指望最后一两年按照高基数缴费,可以领取高养老金。

平均缴费指数计算,是所有实际缴费年限平均的。

④养老保险个人账户的余额,这主要是看前期的积累了。

不过由于缴费基数上下限的影响,过去我们缴费基数较低,因此个人账户积累也不多。

近年来由于缴费基数提高,个人账户记账利率的提升,因此个人账户的余额才在快速积累。

⑤退休年龄确定的计发月数,这实际上是一种晚退多得的体现。

50岁的计发月数是195个月,55岁是170个月,60岁是139个月。

退休越晚,计划越数越小,相同个人账户余额情况下的个人账户养老金就越高。

各地公布的具体方案不同,个人情况也不同,具体需以个人情况及当地有关部门法规为准。

二、河南许昌职工社保卡每年需要缴纳多少?最新如下  社保卡每年交多少?以秦某职工社保为例:  由上图得知,秦某社保卡一年需要缴纳4423.64元,职工个人月缴纳368.64元,若您想要了解明细点击新社通社保计算器,来了解一下明细吧。

》点击新社通app社保计算器,轻松了解你的社保缴费明细!提示:新社通社保计算器计算所得,数据仅供参考。

每个城市每年设定的最低缴纳基数(即劳动者月收入)各有差异,但总体上遵循着相似的原则,即按比例进行缴纳。

龙鱼身上有红点回事:患上出血病?使用敌菌灵医治

不少人都会在家里养上一些观赏鱼,龙鱼就是观赏性比较高的一种鱼类,所以备受人们喜欢。

不过在饲养龙鱼的过程中,可能会遇到龙鱼身上出现红色斑点的情况,这原因是什么呢?一起来了解一下吧。

龙鱼身上有红点如何回事如果龙鱼身上出现了红点,可能是因为龙鱼患上了出血病。

有很多真相会导致龙鱼患上出血病,例如水温太低、水质太差、细菌感染等。

因为龙鱼喜欢生活在温暖的环境里,对水温有着比较高的要求,所以如果饲养龙鱼时长期让龙鱼处于低温的环境当中,龙鱼身体表面就会受到刺激,从而导致有许多红点出现在体表的情况。

此外,龙鱼对水质也有着比较高的要求,如果龙鱼生活的水质有着太多的杂质和脏东西,龙鱼同样会受到刺激,容易患上出血病,从而在身上出现红点。

如果饲养者长时间不给龙鱼换水的话,水质就会逐渐恶化,会有大量的细菌在水里生殖生长,细菌在进入龙鱼身体之后,就会在体表出现充血的情况,身上也就会有很多红点。

龙鱼身上有红点如何医治如果龙鱼身上出现了红点,可能是因为出血病导致的。

这种情况需要饲养者把鱼缸里水的温度提高到26摄氏度以上,同时保持水温的恒定,这样子不会对龙鱼产生刺激。

之后可以将龙鱼转到阳光充足的地方,能够通过光线照射帮助龙鱼杀菌消毒,加快龙鱼痊愈的速度。

如果龙鱼患上出血病的情况比较严重,饲养者还需要将龙鱼捞出来单独医治,可以使用3-5ppm的敌菌灵对患病的龙鱼进行药浴,每次药浴10-15分钟,每天药浴一次,持续一周左右即可痊愈。

感兴趣的朋友还可以了解一下龙鱼嘴巴烂了如何治。

加入收藏
               

使用代理模式模拟ORM实体的延时加载

点击下载文档

格式为doc格式

  • 账号登录
社交账号登录