.NET 工业控制 OPC Matlab

关注工控软件的简单化

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  8 随笔 :: 0 文章 :: 23 评论 :: 3 引用

置顶随笔 #

posted @ 2008-05-19 21:52 TomCat 阅读(2732) 评论(11) 编辑

posted @ 2008-05-18 12:59 TomCat 阅读(2725) 评论(7) 编辑

2008年5月19日 #

    向在汶川地震中死难的同胞默哀!
    在 .NET 中,默认的对象都是上下文敏感对象,他们会被放置在引用他们的宿主的上下文中,如果我们想使用上下文服务,必须使我们的对象放置在提供特定的服务的上下文中,这一类型的对象是面向上下文的对象,这些对象的类必须直接或间接继承自ContextBoundObject类.面向上下文对象在创建时会检查创建宿主的上下文是否提供他所需要的服务,如果宿主不提供需要的服务,那么.NET 将首先创建一个可以提供需要服务的上下文,然后在新创建的上下文中创建对象.
    在.NET 中,跨上下文的访问和Remoting很相似.他们都不直接引用创建的代理,而是使用代理访问另一个上下文中对象.
通常的情况是 客户端 ->透明代理 ->真实代理 ->客户端接收器 ->信道 ->服务器端接收器->堆栈构造 ->面向上下文对象.通过这个调用链,我们可以发现,在跨上下文调用中没有Remoting 中使用的格式器,并且跨上下文调用使用的信道也和Remoting 中的信道不一样,在跨上下文调用中使用CrossContextChannel信道.
    上面的调用链并不完整(大家有兴趣可以查看相关资料),但通过上面的调用链已经可以让我们大致了解.NET 的上下文拦截框架.在.NET中我们可以在客户段接收器和服务端接受器上加入我们自己的消息接收器来实现消息拦截.
.NET为了支持添加消息接收器,提供了类似装饰器的模式,我们在自己的消息接收器类中必须维持一个对下一个消息接收器的引用.
    下面我们就实现一个简单的拦截.为了更直观的展示拦截技术,我们只实现极其简单的功能,就是把方法的调用参数和返回值打印出来,当然打印的方法并不是在客户端,而是在消息接收器中,客户代码和正常代码没有任何区别.
    首先我们要实现接收器.代码如下
   
public class DemoSink : IMessageSink
    
{
        
private IMessageSink m_NextSink;

        
public DemoSink(IMessageSink nextSink)
        
{
            m_NextSink 
= nextSink;
        }


        
IMessageSink 成员
    }
    通过上面的代码可以看出,消息接收器的实现很简单.我们在同步方法调用中,在方法调用前和调用后插入了一些处理,把方法调用参数和返回值打印了出来.
    在实现了消息接收器后,我们还要添加两个类,用于把接收器添加到消息接收链中.
    首先我们要创建一个自定义特性(Attribute)类,使用自定义特性来标注使用上下文拦截是组件(类).这个特性类不能直接继承自Attribute 类,必须继承自 ContextAttribute 类,然后还要创建一个实现接口IContextPropertyIContributeServerContextSink的类.
    两个类的代码如下
   
[AttributeUsage(AttributeTargets.Class)]
    
public class DemoContextAttribute : ContextAttribute
    
{
        
public DemoContextAttribute()
            : 
base("DemoContextAttribute")
        
{
        }


        
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
        
{
            DemoProperty proerty 
= new DemoProperty();
            ctorMsg.ContextProperties.Add(proerty);
        }

        
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
        
{
            DemoProperty property 
= ctx.GetProperty("DemoTest"as DemoProperty;
            
if (property == nullreturn false;
            
else return true;
        }

    }

public class DemoProperty : IContextProperty, IContributeServerContextSink
    
{
        
public DemoProperty()
        
{
        }


        
IContextProperty 成员


        
IContributeServerContextSink 成员
    }

然后我们就可以为指定的组件(类)添加上下文服务了
[DemoContext]
    class Class1 : ContextBoundObject
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }

客户端代码和没有任何改变
class Program
    {
        static void Main(string[] args)
        {
            Class1 c = new Class1();
            int a = c.Add(1, 2);
        }
    }

    上面的代码只是演示上下文拦截技术的实现,在实际编程中,我们可以使用上下文拦截实现把日志管理,角色权限管理,事务管理等一些管道工作从我们的组件(类)代码中剥离,使我们的组件(类)只关注服务的实现,而不需要去关心这些管道工作.
posted @ 2008-05-19 21:52 TomCat 阅读(2732) 评论(11) 编辑

2008年5月18日 #

    在.NET 中,上下文(Context)的概念贯穿着.NET的很多核心内容.他提供了类似运行环境的服务和内容.在.NET中,基于上下文拦截的技术一直是很隐晦的,没有很多的文档说明。然儿,基于上下文的拦截的技术却提供了很好很强大的功能。使我们能方便是实现类似 AOP 的编程模式。.NET3.0 中的WCF更是大量使用了上下文拦截技术。
    在.NET 中,组件服务通常的颗粒是域(Domain)和上下文(Context).其中,在域中提供的服务通常只有'同步域'.当然,.NET 中也提供了很多COM+服务,但需要被服务的组件(类)直接或间接继承自ServicedComponent(被服务的组件)..NET中提供的COM+服务全部在命名空间System.EnterpriseServices中,在其中,提供了诸如消息队列,即时激活,对象池...等服务.
    在使用.NET 开发时,我们都知道我们使用任何一种.NET支持的语言编写的代码都是托管代码.所谓托管代码生成的IL语言只能运行在CLR中.并且享受CLR提供的垃圾回收,托管堆...等.但是,Windows在为我们的IL运行提供一个进程时,并不知道所谓的托管环境,Windows只负责提供进程,在进程中没有托管环境的概念.在Windows 进程和IL之间,域提供了桥梁的作用。在Windows进程中,所有域共享CLR提供的诸如垃圾回收,托管堆,和JIT,加载和卸载程序集等服务。也就是说,我们所有的IL代码必须运行在域中,当然,当我们启动一个.NET程序时,会创建一个默认的域来加载和运行我们的.NET程序,并提供托管堆。我们也可以创建新的域。所以,每个Windows 进程可以宿主多个域。在.NET中,对象是不能够跨域直接引用的,每个.NET对象都是他所属的域所属的托管堆被创建的。对象的跨域访问,必须使用代理(Proxy),并且对象是可以被封送的(直接或间接继承自MarshalByRefObject),跨域访问对象就是所谓的远程访问(Remoting)。
    在.NET中域的粒度仍然很大,如果我们不显式的创建新的域,通常我们程序中的所有组件(类),都运行在同一个域中。在.NET中,上下文(Context),提供了比域粒度更小的运行环境。域可以有多个上下文,但一个上下文只能属于一个域。
和域一样,我们的 .NET组件(类)也必须运行在不同的上下文中,只不过不同的上下文提供不同的上下文服务,每个域中也有一个默认的上下文,默认的上下文但是不提供任何的服务。上下文最大的好处是让我们可以使用上下文拦截技术,为被宿主在上下文的组件(类)提供自定义的服务。这样,我们就可以实现所谓AOP编程。我们可以把AOP中所谓的管道工作作成服务,添加到上固定的下文服务中,这样每个对这个上下文中的组件(类)的调用,都将被拦截,然后把服务(管道方法)添加到组件(类),就好象把服务(管道方法)织入(AOP术语)到组件(类)中.

posted @ 2008-05-18 12:59 TomCat 阅读(2725) 评论(7) 编辑

2008年1月21日 #

    我们在使用 Composite 模式组织设备管理时,对现实中的设备进行抽象是很大的挑战.我们会设计一个基类,然后根据设备的特性设计各种类型的设备的继承关系,然后各种设备再继承这些子类.(标准OOP设计)
    其实在面向对象的编程中,使用继承本身就有很大的挑战,我们必须把基类设计的很稳定,基类的稳定性和我们对对象的了解和对对象未来变化的了解有直接的关系,我们必须使我们的基类在适应未来的变换没有大的修改,这样才能减少因为对基类的修改对继承类的影响.
    这就象我们用积木摆一个倒三角型(∨),在面对现实中千差万别的设备和未来会出现的设备时,很难维持这个类的模型.
    另外过多的类和继承关系本身对 Composite 模式对象的管理也是一种挑战(比如使用 Vistor 模式).
    把对设备的管理和设备本身的抽象分开是一个很好的解决办法.
    实际上我们在实际设计中使用了 Bridge 模式.
    首先我们定义了一个接口
    public interface IDeviceDriver
    {
          ......// 定义对设备的基本操作方法
    }
    然后在 Device 类里添加一个属性
    IDeviceDriver DeviceDriver { get;}
    这样,我们就把对设备的抽象从设备本身分离开,由实现 IDeviceDriver 或继承接口的设备驱动类负责对设备的操作.
    使用 Birdge 模式把设备的抽象分离出来后,在设备管理中我们只要维持很少的类和继承关系. 
    Component 类,DeviceNode 类和Device 类.为了管理的方便添加了 DeviceRootNode 类,他继承 DeviceNode 类,
只是重写 Parent 属性,使他指向一个空引用.作为所有对象的顶层父对象
    这样,我们在用 Composite 模式实现设备管理时,只维持了4个类.极大简化了代码.
    为了扩展系统的使用,我们公开 IDeviceDriver 接口,允许用户实现 IDeviceDriver 接口来开发特定设备的驱动程序.
posted @ 2008-01-21 09:59 TomCat 阅读(61) 评论(0) 编辑

2008年1月10日 #

    /// <summary>
    /// PS: 在写这个文章时想用的标题是 Composite 模式和其他模式,后来感觉想写的不只是其他模式的关系
    /// 就写了这个标题,好象语法不通,但没办法,从中学开始语文考试就没超过60分^-^
    /// </summary>
    当使用抽象类的时候我们可以先定义一个 Component 抽象类
, 在类里加了两个重载的方法 IsTree
用于判断合成对象是否的树结构.
    public abstract class Component
    {
            private string _strName = string.Empty;
            private Component _parent; // 父对象

            public Component(string name)
            {
                  this._strName = name;
            }
            public string Name{get {return this._strName;}}
            public Component Parent{get{return this._parent;}}
            public bool IsTree()
            {
                   return this.IsTree(new Hashtable());
            }
            public abstract bool IsTree(Hashtable visited);

    }
    在 Composite 类和 Leaf 类里实现  IsTree 方法都很简单,只要检查 Coomposite 对象的 Name 是否在访问的哈希表中出现过,并且要检查 COmposite 对象的子对象是否是树结构
    public class Composite : Component
    { 
           private IList _listChild;
           public Composite(string name):base(name){}
 
           public IList ChildComponentItems
           {
                  get{return this._listChild;}
           }

           public override bool IsTree(Hashtable visited)
          {
            visited.Add(this.Name, this);
            foreach (Component dc in this.ChildComponentItems)
            {
                if (visited.Contains(dc.Name) || !dc.IsTree(visited))
                {
                    return false;
                }
            }
            return true;
        }

    } 
    在 Leaf 类里就更简单了,因为 Leaf 对象本身肯定是树结构,只要在访问的哈希表中记录 Leaf 对象的 Name 就可以了
    public class Leaf : Component
    {
            public Leaf(string name):base(name){}
            
            public override bool IsTree(Hashtable visited)
            {
                  visited.Add(this.Name, this);
                  return true;
            }

    }
    现在.我们的合成模式可以判断是否是树结构了.
    现在我们终于能开始考虑第二个思想了(是思想不是法律!!!,不实现不违法!)
    他让我们把合成对象和叶对象的操作提供一个统一的接口或抽象,苍天哪!
    在 Composite 模式中有几个常用的操作 
        public bool Contains(string name);
        public Component Find(string name);
        public int GetDeviceCount();
    实现了这些操作或方法后,我们就要对合成对象和叶对象进行抽象了,具体怎么抽象,抽象什么和我们的合成对象的应用有关. 
    第一次应用 Composite 模式是在做工业控制项目中用于设备管理.在设备管理中要求实现设备树.其中节点就是合成对象,他可以添加设备或其他的节点,设备就是叶(在实际中,还有总线设备,他也可以添加设备,为了讨论方便,这里就把他排除在外).
    OK,现在就对这些节点和设备抽象了.

    首先看抽象什么,在对设备来说有一些常规操作比如 连接断开设备,打开关闭设备和读写设备等.这些我们可以把他抽象到顶层抽象类 Component 中.在 Leaf 类里实现这些抽象方法是直接操作设备,在节点里是通过迭代操作节点里的所有设备
    这样我可以对节点和设备使用同一个抽象来操作,比如我们可以选择打开一个设备,也可以打开一个节点下的所有设备.两种操作对使用合成对象的客户代码是一样的.
    可有些对设备的操作比较特殊,不适合在节点里对成批的设备同时操作(这种情况在其他的合成对象也会遇到),这些方法需要抽象到 Component 类里吗? 郁闷第二次.如果把这些操作都抽象到 Component 类里,Component 类会不会很变态?

    同时,现实中设备千差万别,我们怎么对这些设备进行抽象.或者说,我们要把 Leaf 作为其他设备类的顶层抽象.那 Leaf 要有那些功能.怎么把各种设备的操作抽象到 Leaf 中,还有怎么根据设备的主要特性设定设备子类的继承关系,比如我们可以根据设备的连接形式来确定设备子类的继承关系
    比如对于板卡类的设备,我可以定义一个类继承 Leaf 类
    public class CardDevice : Leaf
    {
          ......
    }
    在这个类里,我们会实现板卡通讯的基本功能
    同时对于 RS323(串口)连接的设备,我们可以定义一个类,同样继承 Leaf  类
    public class RS232Device : Leaf
    {
          .......
    }
    在 RS232Device 类里我们实现了和 RS232 口通讯的基本功能,
    这样我们在扩充设备时,如果设备是用板卡的就可以继承 CardDevice 类,同样如果设备使用 RS232 口就可以继承 RS232Device 类. 很好的解决方案,不是吗?
    确实不是!
    假如我们板卡和串口的通讯方式都有了新的版本,为了实现新的版本我们重新定义两个类来扩充新的协议,
    public class CardDevice2 : CardDevice 
    {
          ......
    }
    public class RS232Device2 : RS232Device 
    {
          .......
    }

    假如板卡的扩充和串口的扩充都增加了一个相同的控制方式,比如都可以用很通用命令让设备说 "Hello World",很夸张.哈哈.那这个方式在以前的版本实现不了,那么我们就要在 CardDevice2 和 RS232Device 类都要实现,并且两个类里的代码几乎是一致的,那么代码重用在这里只能表现为粘贴和复制了.
    幸好还个 桥接(Bridge)模式,他的广告词是: 将抽象部分与实现部分分离,使它们都可以独立的变化.
    好象我们能用来解决这个问题.买东西不能看广告,要看疗效.究竟 Bridge 模式能解决我们的问题吗? 谁用谁知道.哈哈.
   

posted @ 2008-01-10 16:05 TomCat 阅读(99) 评论(1) 编辑

2008年1月9日 #

    Composite 模式在设计模式里属于比较容易理解和实现的模式了,实现一个Composite模式很简单,我们能使用很少的代码就实现了 Composite  模式,但 Composite  模式确带来了很多问题或是思考.
    Composite 模式有两个重要的思想.合成要既可以包含单项也可以包含单项的集合或集合的集合(就叫他合成吧).第二个重要的思想是为单独的项和合成定义相同的行为.这样我们访问 Composite  的对象时(不管是合成或是叶) 都可以使用同一个接口或抽象.
    在使用Composite 模式时我们会首先定义三个基本的类,顶层抽象类 Component,合成 Composite,叶(感觉还是叫叶比较形象)Leaf.
    如果只考虑合成的两个思想我们在设计 Composite 模式的顶层抽象时可以使用接口
     public interface IComponent
     {
     }
     (名字和.NET 的 System.ComponentModel.IComponent 有冲突,不怕咱有命名空间 ^-^)
     为了实现第一个思想我们可以在接口中加入两个方法
     public interface IComponent
     {
             void AddComponent(IComponent component);
             void RemoveComponent(IComponent component);
     }
     然后我们定义两个类 Composite 和 Leaf 实现这个接口.
     好了,到现在我们实现了一个最简易的 Composite  模式.现在这一个接口和俩类能干嘛,嘛也干不了.
     为了能在合成对象中添加合成对象或叶对象我们需要在 Composite 类中定义一个 IList 对象存放这些添加到这个合成对象的合成对象或叶(饶口令),然后实现接口里的俩方法.
    那 Leaf 类需要这个变量吗 ? 当然不需要,叶里什么也不能加啊,可既然叶不能添加别的对象,就是说
    void AddComponent(IComponent component);
    void RemoveComponent(IComponent component); 这两个方法在叶 Leaf 类里没有任何作用,干嘛我们要实现他,
为什么不能把这两个方法在 Composite 类中定义呢,这好象又和 Composite 模式的第二个思想有点不符啊.郁闷. 
    在实际应用中,很少会用接口来实现顶层的抽象,因为我们在访问  Composite 中的对象时会用到迭代器或使用 Vistor 模式(最有争议的模式),这时候如果我们的 Composite 模式的对象不是树结构的话,就会进入死循环.所有我们一般使用抽象类实现顶层的抽象,并在类中加入判断合成是否是树结构的方法.... (今天连写了两篇文章,比我去年文章的总和还多^-^)还是明天在接着写吧
posted @ 2008-01-09 22:11 TomCat 阅读(302) 评论(1) 编辑

posted @ 2008-01-09 19:55 TomCat 阅读(585) 评论(0) 编辑

2008年1月8日 #

posted @ 2008-01-08 21:29 TomCat 阅读(284) 评论(3) 编辑

posted @ 2008-01-08 14:20 TomCat 阅读(57) 评论(1) 编辑