Attribute在.net编程中的应用(五)

来源:互联网 发布:淘宝助理如何描述宝贝 编辑:程序博客网 时间:2024/06/05 06:41

Attribute在拦截机制上的应用

从这一节开始我们讨论Attribute的高级应用,为此我准备了一个实际的例子:我们有一个订单处理系统,当一份订单提交的时候,系统检查库存,如果库存存量满足订单的数量,系统记录订单处理记录,然后更新库存,如果库存存量低于订单的数量,系统做相应的记录,同时向库存管理员发送邮件。为了方便演示,我们对例子进行了简化:

//Inventory.csusing System;using System.Collections;namespace NiwalkerDemo{   public class Inventory   {      private Hashtable inventory=new Hashtable();            public Inventory()      {         inventory["Item1"]=100;         inventory["Item2"]=200;      }      public bool Checkout(string product, int quantity)      {         int qty=GetQuantity(product);          return qty>=quantity;      }            public int GetQuantity(string product)      {         int qty=0;         if(inventory[product]!=null)            qty = (int)inventory[product];         return qty;      }            public void Update(string product, int quantity)      {         int qty=GetQuantity(product);         inventory[product]=qty-quantity;      }   }}//Logbook.csusing System;namespace NiwalkerDemo{   public class Logbook   {      public static void Log(string logData)      {         Console.WriteLine("log:{0}",logData);      }   }}//Order.csusing System;namespace NiwalkerDemo{   public class Order   {      private int orderId;      private string product;      private int quantity;            public Order(int orderId)      {         this.orderId=orderId;      }            public void Submit()      {         Inventory inventory=new Inventory(); //创建库存对象                  //检查库存         if(inventory.Checkout(product,quantity))         {            Logbook.Log("Order"+orderId+" available");            inventory.Update(product,quantity);         }         else         {            Logbook.Log("Order"+orderId+" unavailable");            SendEmail();         }      }            public string ProductName      {         get{ return product; }         set{ product=value;  }      }            public int OrderId      {         get{ return orderId; }      }            public int Quantity      {         get{ return quantity;}         set{ quantity=value; }      }            public void SendEmail()      {         Console.WriteLine("Send email to manager");      }   }}

下面是调用程序:

//AppMain.csusing System;namespace NiwalkerDemo{   public class AppMain   {      static void Main()      {         Order order1=new Order(100);         order1.ProductName="Item1";         order1.Quantity=150;         order1.Submit();                  Order order2=new Order(101);         order2.ProductName="Item2";         order2.Quantity=150;         order2.Submit();      }   }}

程序看上去还不错,商务对象封装了商务规则,运行的结果也符合要求。但是我好像听到你在抱怨了,没有吗?当你的客户的需求改变的时候(客户总是经常改变他们的需求),比如库存检查的规则不是单一的检查产品的数量,还要检查产品是否被预订的多种情况,那么你需要改变Inventory的代码,同时还要修改Order中的代码,我们的例子只是一个简单的商务逻辑,实际的情况比这个要复杂的多。问题在于Order对象同其他的对象之间是紧耦合的,从OOP的观点出发,这样的设计是有问题的,如果你写出这样的程序,至少不会在我的团队里面被Pass.

你说了:“No problem! 我们可以把商务逻辑抽出来放到一个专门设计的用来处理事务的对象中。”嗯,好主意,如果你是这么想的,或许我还可以给你一个提议,使用Observer Design Pattern(观察者设计模式):你可以使用delegate,在Order对象中定义一个BeforeSubmit和AfterSubmit事件,然后创建一个对象链表,将相关的对象插入到这个链表中,这样就可以实现对Order提交事件的拦截,在Order提交之前和提交之后自动进行必要的事务处理。如果你感兴趣的话,你可以自己动手来编写这样的一个代码,或许还要考虑在分布式环境中(Order和Inventory不在一个地方)如何处理对象之间的交互问题。

幸运的是,.NET Framework中提供了实现这种技术的支持。在.NET Framework中的对象Remoting和组件服务中,有一个重要的拦截机制,在对象Remoting中,不同的应用程序之间的对象的交互需要穿越他们的域边界,每一个应用域也可以细分为多个Context(上下文环境),每一个应用域也至少有一个默认的Context,即使在同一个应用域,也存在穿越不同Context的问题。NET的组件服务发展了COM+的组件服务,它使用Context Attribute来实现象COM+一样的拦截功能。通过对调用对象的拦截,我们可以对一个方法的调用进行前处理和后处理,同时也解决了上述的跨越边界的问题。

需要提醒你,如果你在MSDN文档查ContextAttribute,我可以保证你得不到任何有助于了解ContextAttribute的资料,你看到的将是这么一句话:“This type supports the .NET Framework infrastructure and is not intended to be used directly from your code.”——“本类型支持.NET Framework基础结构,它不打算直接用于你的代码。”不过,在msdn站点,你可以看到一些有关这方面的资料(见文章后面的参考链接)。

下面我们介绍有关的几个类和一些概念,首先是:

ContextAttribute类

ContextAttribute派生自Attribute,同时它还实现了IContextAttribute和IContextProperty接口。所有自定义的ContextAttribute必须从这个类派生。构造器:ContextAttribute:构造器带有一个参数,用来设置ContextAttribute的名称。

公共属性:Name:只读属性。返回ContextAttribute的名称

公共方法:GetPropertiesForNewContext:虚拟方法。向新的Context添加属性集合。IsContextOK:虚拟方法。查询客户Context中是否存在指定的属性。IsNewContextOK:虚拟方法。默认返回true。一个对象可能存在多个Context,使用这个方法来检查新的Context中属性是否存在冲突。Freeze:虚拟方法。该方法用来定位被创建的Context的最后位置。

ContextBoundObject类

实现被拦截的类,需要从ContextBoundObject类派生,这个类的对象通过Attribute来指定它所在Context,凡是进入该Context的调用都可以被拦截。该类从MarshalByRefObject派生。

以下是涉及到的接口:

IMessage:定义了被传送的消息的实现。一个消息必须实现这个接口。

IMessageSink:定义了消息接收器的接口,一个消息接收器必须实现这个接口。还有几个接口,我们将在下一节结合拦截构架的实现原理中进行介绍

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 取票学生证没带怎么办 学生卡的失磁怎么办 学生证没有充磁买不了学生票怎么办 买学生票不在优惠区间怎么办 火车票学生优惠次数用完怎么办 学生乘火车优惠磁卡丢了怎么办 磁卡锁的卡丢了怎么办 电梯磁卡扣丢了怎么办 买火车票手机号填错了怎么办 买火车票乘客身份核验失败怎么办 火车票不在一个车厢怎么办站票 坐火车丢东西了怎么办 g2坐过站了怎么办 坐火车买近了怎么办 打印的纸质火车票丢失怎么办 格力空调没保修单怎么办 格力空调不兑现保修怎么办 哈空调如果退市怎么办 空调保修单丢了怎么办 海尔空调发票丢了怎么办 格力空调发票丢了怎么办 联程航班第一程延误怎么办 飞机经停10小时怎么办 去车站买票没带身份证怎么办 转机航班第一班延误了怎么办 转机航班第一班取消了怎么办 香港转机大陆行李托运怎么办 联程车票第一班车晚点怎么办 到了普吉机场接机怎么办 被骚扰电话打个不停怎么办 网贷不停发信息怎么办 网贷天天发信息怎么办 诈骗电话一直打个不停怎么办 寄快递电话号码写错了怎么办 寄快递收件人号码错了怎么办 嫒和媛分不清楚怎么办 快递柜单号没了怎么办 邮政蜜蜂箱 退件怎么办 手机狂收验证码怎么办 快递柜超过24小时怎么办 快递柜短信删了怎么办