Effective C#: 4.使用类厂(Class Factory)模式实现基于接口的客户激活远程对象(下)

** Effective C#: 4.使用类厂(Class Factory)模式实现 **

基于接口的客户激活远程对象(下)

陈铭 Microsoft C#/.NET Asia MVP

难度:7/10 条款3

至此,关于 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

  1<enter> to exit..."); 
  2
  3System.Console.ReadLine(); 
  4
  5return 0; 
  6
  7} 
  8
  9} 
 10
 11} 
 12
 13//client.cs, Client Side code 
 14
 15using System; 
 16
 17using System.Runtime.Remoting; 
 18
 19using System.Runtime.Remoting.Channels; 
 20
 21using System.Runtime.Remoting.Channels.Tcp; 
 22
 23namespace Effective.CSharp.Chapter4 { 
 24
 25public class Client 
 26
 27{ 
 28
 29public static int Main() 
 30
 31{ 
 32
 33TcpChannel chan = new TcpChannel(); 
 34
 35ChannelServices.RegisterChannel(chan); 
 36
 37//Register at client side 
 38    
 39    
 40                RemotingConfiguration.RegisterActivatedClientType(
 41    
 42    
 43    typeof(RemoteObject),                                                  "tcp://localhost:8085/MyServer");
 44
 45//Create the remote object 
 46
 47RemoteObject obj = new RemoteObject(); 
 48
 49Console.WriteLine(obj.SayHello("World")); 
 50
 51return 0; 
 52
 53} 
 54
 55} 
 56
 57} 
 58
 59显然,在  CAO  对象的编译和发布方面,我们会碰到与  SAO  对象完全相同的问题。  Client.cs  的编译和运行离不开  share.dll  。  CAO  对象的应用还有几处明显的不同:  CAO  对象不仅要求在服务器端进行注册,而且在客户端也需要完成一定的注册工作;更重要的是,  CAO  对象是通过  new  创建的!后者彻底阻断了简单的通过接口解决问题的幻想——不可能通过  new  创建出接口的实例,而必须显式的指明要创建的实现特定接口的类型名称! 
 60
 61![NOTE](http://upload.eraserver.net/qqchen79/ECS/remoting.gif)
 62
 63很高兴看到你愿意进一步深入了解  .NET Remoting  的具体运作。  J 
 64
 65先来看一下  .NET  内部是如何根据客户请求创建  CAO  对象的。  .NET Remoting  服务会注册一个通用的  Singleton SAO  对象,用于处理所有创建  CAO  对象的请求。这个  SAO  对象实现了  IActivator  接口,其缺省  URI  为  _ <application name=""> _ /RemoteActivationService.rem  ,其中  application name  可以通过  RemotingConfiguration. ApplicationName  进行设置。 
 66
 67当客户程序执行  new  语句创建远程对象时,实际上客户端的  .NET Remoting  服务会通过远程对象的  URL  地址连接到服务器端相应的  RemoteActivationService.rem  入口  (  上面的例子中是  "tcp://localhost:8085/MyServer/RemoteActivationService.rem")  ,调用  SAO  对象  IActivator  接口的  Activate  方法;  Activate  方法会根据参数查找所有在服务器端注册过的  CAO  对象类型,如果找到相对应的注册信息  (  包括类型名称、所在的类集以及版本等  )  ,  Activate  就会根据这些信息创建一个该对象的实例,并且为新创建的对象生成一个唯一的  URI  入口,然后将该对象返回给客户端。这样,此后的客户方法调用就会与这个特定的  CAO  对象实例对应起来。  (  其中为新生成对象指定  URI  的部分会由底层的  .NET Remoting  服务自动完成,  Activate  需要做的仅仅是生成一个新的对象,并且返回该对象的引用  )  。 
 68
 69可见,远程对象的客户激活机制仅仅是架设在  SAO  基础上的一层包装,在简化程序员工作的同时,这种客户激活机制也剥夺了对  CAO  对象使用接口和抽象基类的权力。既然  .NET  对  CAO  对象的实现没有用到任何特别的方法,我们就完全可以模仿系统实现自己的  CAO  机制,只需少许更改,就可以为子定义的  CAO  提供基于接口的创建方法。 
 70
 71不难看出在整个  CAO  实现体系中,  IActivator  实际上是作为一个通用类厂  (Class Factory)  接口出现的,所以我们也需要针对  IRemoteObject  接口定义自己的类厂接口  IRemoteFactory: 
 72
 73//share.cs, Remote Object and Factory interface 
 74
 75namespace Effective.CSharp.Chapter4 { 
 76
 77public interface IRemoteObject { 
 78
 79string SayHello(string name); 
 80
 81} 
 82
 83public interface IRemoteFactory { 
 84
 85IRemoteObject CreateInstance(); 
 86
 87} 
 88
 89} 
 90
 91在服务器端的代码中,我们需要实际实现  RemoteObject  和一个用于创建  RemoteObject  的类厂,并且将后者注册为  SAO  对象: 
 92
 93//server.cs, Server side code 
 94
 95using System.Runtime.Remoting; 
 96
 97using System.Runtime.Remoting.Channels; 
 98
 99using System.Runtime.Remoting.Channels.Tcp; 
100
101namespace Effective.CSharp.Chapter4 { 
102
103public class RemoteObject: MarshalByRefObject, 
104
105IRemoteObject { 
106
107public string SayHello(string name) { 
108
109return “Hello, “ + name; 
110
111} 
112
113} 
114
115public class RemoteFactory: MarshalByRefObject, 
116
117IRemoteFactory { 
118
119public IRemoteObject CreateInstance() { 
120
121return new RemoteObject(); 
122
123} 
124
125} 
126
127public class Server { 
128
129public static int Main() { 
130
131//Register the channel 
132
133TcpChannel chan = new TcpChannel(8085); 
134
135ChannelServices.RegisterChannel(chan); 
136
137//Register the client activated remote class 
138
139RemotingConfiguration.RegisterWellKnownServiceType( 
140
141typeof(RemoteFactory), 
142
143"MyFactory.rem", WellKnownObjectMode.Singleton); 
144    
145    
146     
147
148//Hold the server, wait for client 
149
150System.Console.WriteLine("Hit <enter> to exit..."); 
151
152System.Console.ReadLine(); 
153
154return 0; 
155
156} 
157
158} 
159
160} 
161
162最后,客户端的实现代码也略有不同:必须先通过  Activator.GetObject  得到  IRemoteFactory  接口,然后在需要创建  RemoteObject  的时候调用  IRemoteFactory.CreateInstance  : 
163
164//client.cs, Client Side code 
165
166using System; 
167
168using System.Runtime.Remoting; 
169
170using System.Runtime.Remoting.Channels; 
171
172using System.Runtime.Remoting.Channels.Tcp; 
173
174namespace Effective.CSharp.Chapter4 { 
175
176public class Client 
177
178{ 
179
180public static int Main() 
181
182{ 
183
184TcpChannel chan = new TcpChannel(); 
185
186ChannelServices.RegisterChannel(chan); 
187
188IRemoteFactory  factory = 
189
190(  IRemoteFactory  )Activator.GetObject( 
191    
192    
193    typeof(IRemoteFactory), "tcp://localhost:8085/MyFactory");             
194
195//Create the remote object 
196
197RemoteObject obj = factory.CreateInstance(); 
198
199Console.WriteLine(obj.SayHello("World")); 
200
201return 0; 
202
203} 
204
205} 
206
207} 
208
209在以上所有应用接口的实例当中,我们同样可以使用抽象基类代替接口  (  关于抽象基类和接口的比较,详见条款  X)  。 
210
211对于应用  .NET Remoting  技术的分布式应用程序开发,使用接口以及基于接口的类厂是比较好的设计方案,因为这种方案不仅提供了更加清晰的应用模块结构,而且具有更好的可扩展性。 
212
213* 本文系原创作品,未经作者本人许可请勿转载。</enter></application></enter>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus