C# 代理工厂(2)

 

至此,关于SAO对象编译和发布的问题已经解决。再让我们回过头来看一下关于CAO对象的类似问题,是否可以同样通过使用接口来解决问题呢?

照例,我们从一个完整的应用实例开始:

//share.cs, Remote Object

namespace Effective.CSharp.Chapter4 {

    //Exactly same as the original one

    public class RemoteObject : System.MarshalByRefObject {

         //a very simple method implementation

        public string SayHello(string name) {

            return "Hello, " + name;

        }

    }

} 

//server.cs, Server side code

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

 

namespace Effective.CSharp.Chapter4 {

    public class Server {

        public static int Main() {

            //Register the channel

            TcpChannel chan = new TcpChannel(8085);

            ChannelServices.RegisterChannel(chan);

 

            //Register the client activated remote class

            RemotingConfiguration.ApplicationName = “MyServer”;

                 RemotingConfiguration.RegisterActivatedServiceType(
   
   
                               typeof(RemoteObject));
   
   

              

               //Hold the server, wait for client

            System.Console.WriteLine("Hit <enter> to exit...");

            System.Console.ReadLine();

            return 0;

        }

    }

}

 

//client.cs, Client Side code

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

 

namespace Effective.CSharp.Chapter4 {

  public class Client

  {

    public static int Main()

    {

         TcpChannel chan = new TcpChannel();

      ChannelServices.RegisterChannel(chan);

 

      //Register at client side

            RemotingConfiguration.RegisterActivatedClientType(
   
   
typeof(RemoteObject),                                                  "tcp://localhost:8085/MyServer");
   
   

 

      //Create the remote object

RemoteObject obj = new RemoteObject();

     Console.WriteLine(obj.SayHello("World"));

         return 0;

    }

  }

} 

显然,在CAO对象的编译和发布方面,我们会碰到与SAO对象完全相同的问题。Client.cs的编译和运行离不开share.dllCAO对象的应用还有几处明显的不同:CAO对象不仅要求在服务器端进行注册,而且在客户端也需要完成一定的注册工作;更重要的是,CAO对象是通过new创建的!后者彻底阻断了简单的通过接口解决问题的幻想——不可能通过new创建出接口的实例,而必须显式的指明要创建的实现特定接口的类型名称!

NOTE

    很高兴看到你愿意进一步深入了解 .NET Remoting 的具体运作。 J

先来看一下.NET内部是如何根据客户请求创建CAO对象的。.NET Remoting服务会注册一个通用的Singleton SAO对象,用于处理所有创建CAO对象的请求。这个SAO对象实现了IActivator接口,其缺省URI<application name>/RemoteActivationService.rem,其中application name可以通过RemotingConfiguration. ApplicationName进行设置。

当客户程序执行new语句创建远程对象时,实际上客户端的.NET Remoting服务会通过远程对象的URL地址连接到服务器端相应的RemoteActivationService.rem入口(上面的例子中是"tcp://localhost:8085/MyServer/RemoteActivationService.rem"),调用SAO对象IActivator接口的Activate方法;Activate方法会根据参数查找所有在服务器端注册过的CAO对象类型,如果找到相对应的注册信息(包括类型名称、所在的类集以及版本等)Activate就会根据这些信息创建一个该对象的实例,并且为新创建的对象生成一个唯一的URI入口,然后将该对象返回给客户端。这样,此后的客户方法调用就会与这个特定的CAO对象实例对应起来。(其中为新生成对象指定URI的部分会由底层的.NET Remoting服务自动完成,Activate需要做的仅仅是生成一个新的对象,并且返回该对象的引用) 

可见,远程对象的客户激活机制仅仅是架设在SAO基础上的一层包装,在简化程序员工作的同时,这种客户激活机制也剥夺了对CAO对象使用接口和抽象基类的权力。既然.NETCAO对象的实现没有用到任何特别的方法,我们就完全可以模仿系统实现自己的CAO机制,只需少许更改,就可以为子定义的CAO提供基于接口的创建方法。 

不难看出在整个CAO实现体系中,IActivator实际上是作为一个通用类厂(Class Factory)接口出现的,所以我们也需要针对IRemoteObject接口定义自己的类厂接口IRemoteFactory:

//share.cs, Remote Object and Factory interface

namespace Effective.CSharp.Chapter4 {

    public interface IRemoteObject {

string SayHello(string name);

    }

 

    public interface IRemoteFactory {

         IRemoteObject CreateInstance();

 }

}

在服务器端的代码中,我们需要实际实现RemoteObject和一个用于创建RemoteObject的类厂,并且将后者注册为SAO对象: 

//server.cs, Server side code

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

 

namespace Effective.CSharp.Chapter4 {

    public class RemoteObject: MarshalByRefObject,

    IRemoteObject {

            public string SayHello(string name) {

                  return “Hello, “ + name;

}

 }

 

 public class RemoteFactory: MarshalByRefObject,

                             IRemoteFactory {

      public IRemoteObject CreateInstance() {

            return new RemoteObject();

}

 }

                          

    public class Server {

         public static int Main() {

            //Register the channel

            TcpChannel chan = new TcpChannel(8085);

            ChannelServices.RegisterChannel(chan);

 

            //Register the client activated remote class

            RemotingConfiguration.RegisterWellKnownServiceType(

typeof(RemoteFactory),

"MyFactory.rem", WellKnownObjectMode.Singleton);

 
     
     

              

               //Hold the server, wait for client

            System.Console.WriteLine("Hit <enter> to exit...");

            System.Console.ReadLine();

            return 0;

        }

    }

} 

最后,客户端的实现代码也略有不同:必须先通过Activator.GetObject得到IRemoteFactory接口,然后在需要创建RemoteObject的时候调用IRemoteFactory.CreateInstance 

//client.cs, Client Side code

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

 

namespace Effective.CSharp.Chapter4 {

  public class Client

  {

    public static int Main()

    {

         TcpChannel chan = new TcpChannel();

      ChannelServices.RegisterChannel(chan);

IRemoteFactory factory =

(IRemoteFactory)Activator.GetObject(

typeof(IRemoteFactory), "tcp://localhost:8085/MyFactory");             
     
     

 

      //Create the remote object

RemoteObject obj = factory.CreateInstance();

     Console.WriteLine(obj.SayHello("World"));

         return 0;

    }

  }

} 

在以上所有应用接口的实例当中,我们同样可以使用抽象基类代替接口(关于抽象基类和接口的比较,详见条款X) 

对于应用.NET Remoting技术的分布式应用程序开发,使用接口以及基于接口的类厂是比较好的设计方案,因为这种方案不仅提供了更加清晰的应用模块结构,而且具有更好的可扩展性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值