|   现在,您所拥有的函数可以实现通用目标,该函数能够为您提供一个与指定符号名相对应的对象。此实用函数被称作工厂服务。不过这仅仅是工厂服务的简单框架。我们将以此为基础作进一步的扩展,以便能够覆盖更多的情况,争取实现最大限度的利用 
       形式化的工厂服务  我们将需求形式化为一个工厂服务接口。  public interface IFactory{
 public Object getObject(string symbolicname):
 }
 
 所以,工厂服务将返回指定符号名所对应的对象。
 使用缓存增强工厂服务  假设这样一种情况:现在有两个客户端正在尝试使用工厂服务登录到应用程序。具体情形如下所述:  //client1IFactory fact;
 LoggingInterface log = (LoggingInterface)fact.getObject(
 "logger");
 log.logMessage("Message from client1");
 //client2
 IFactory fact;
 LoggingInterface log = (LoggingInterface)fact.getObject(
 "logger");
 log.logMessage("Message from client2");
 
 同时假定使用FileLogger 作为我们的实现工具。所以现在的问题就是,您预期在应用程序中会有多少 FileLogger对象呢?如果两个客户端能够共享同一对象,这是非常理想的结果。因此,工厂服务就应该将这一要求考虑在内,对所请求的对象进行缓冲存储。但是,工厂服务如何才能知道要对该对象进行缓冲存储?这就需要为工厂服务提供必要的线索,以便使其明确该类在整个应用程序中 
        只有一个实例。
 要做到这一点,可以采用以下两种方式:  一种方法就是更改配置,如下所示:  ·<request name="logger'>· <classname>EventLogger</classname>
 · <instance-count>single|multiple</instance-count>
 ·</request>
 
 现在工厂服务就能够确定是否需要将此 instance-count 读取到缓存。
 另一种实现方法如下所示:  ·public class FileLogger : LoggingInterface, · SingeInstanceInterface
 ·{
 · ...
 ·}
 
 SingleInstanceInterface是一个接口标记,FileLogger使用该接口标记来告知工厂服务该对象设计为单实例,因此工厂服务可以放心地对此对象进行缓冲存储。
 以上这两种方法有一个很重要的不同之处。 例如,如果假定支持多实例,您很可能会将 FileLogger 设计成不对线程进行检测。同时,负责管理配置文件的人员却将“多实例”错误地更改为“单实例”。这样的话,就可能会引发线程问题。 
       一个类确定为单实例还是多实例成为设计时一个很重要的限制。我个人认为,将其表述为一个接口标记更为合适。接口标记仅仅只是一个名称而已,它主要用来说明所提到的接口中没有任何方法。 
       接下来,我们来定义缓存描述。  public interface SingleInstanceInterface {}public interface MultiInstanceInterface {}
 
 如果我们所提及的类并没有实现上述的任何一个接口,则默认为MultipleInstanceInterface接口。
 使用初始化改善工厂  到目前为止,我始终未提及 FileLogger的一个很重要的细节。下面,我们再来看一下配置文件吧:  <request name="logger'><classname>FileLogger
 </request>
 
 您已经开始使用如下所示的代码:
 IFactory fact;LoggingInterface log = (LoggingInterface)fact.getObject(
 "logger");
 log.logMessage("Message from client2");
 
 现在有这样一个问题:FileLogger。如何才能知道要写入到哪一个文件呢?因为工厂并不负责将某一参数传递给FileLogger类。接下来我们来研究一种很明显的情形。我们为什么不选择通过修改工厂服务来将参数传递给getObject 
        方法,以便此方法能够将参数传递给FileLogger?为了实现上述目标,上面的函数应该为:
 IFactory fact;LoggingInterface log = (LoggingInterface)fact.getObject(
 "logger", "filename");
 log.logMessage("Message from client2");
 
 如果想将日志更改为 EventLogger又该怎么办呢? 实际上,这些附加参数可能会违反工厂服务的约定。所以,我们将不得不使用另一可选方法。我们首先来看看第一个示例:
 public class FileLogger{
 FileLogger(string filename);
 FileLogger() // default constructor, one that the
 // factory is interested in
 {
 // read the filename from config
 IConfig cfg..
 string filename = cfg.getValue("/Logging/filename",null);
 this(filename);
 }
 }
 
 要实现上述所描述的内容,您还需要具备以下配置:
 <request name="logger'><classname>FileLogger</classname>
 </request>
 <Logging>
 <filename>abc</filename>
 </Logging>
 
 现在我们要回过头来解决前面遗留的问题:配置信息作为FileLogger的一部分在其他地方也将会提到。那么。我们又打算如何来解决该问题呢?首先,我们将配置设为:
 <request name="logger'><classname>FileLogger</classname>
 <filename>abc</filename>
 </request>
 
 下面使用下列接口来处理FileLogger 类:
 public interface InitializableInterface{
 public void initialize(string requestname, IConfig cfg);
 }
 public class FileLogger :
 LoggingInterface
 // main job
 ,SingleInstaceInterface
 // only one copy exists
 ,InitializableInterface
 // we will see now what this is
 {
 private string filename;
 FileLogger();
 public void initialize(string requestname, IConfig cfg)
 {
 filename = cfg.getValue("/request/" + requestname +
 "/filename",null);
 .. other initialization stuff
 }
 }
 
 与工厂相关的接口 现在,我们来对工厂服务所涉及的接口进行简单的总结。请注意:为了方便起见,以下将使用"I" 来代表接口。
 public interface IFactory{
 // Instantiates an object and returns it
 public object getObject(string symbolicName);
 .. More methods to be covered in subsequent articles
 }
 public interface ISingleInstance {}
 // Indicates to the factory that the intantiated object
 // needs to be cached
 public interface IMultiInstance {}
 // Object can not be cached
 public interface IInitializable
 {
 // used to read further unified configuration information
 public void initialize(string symbolicname);
 }
 
 使用上述工厂服务实现组件 我们可以将组件看作是一类方法的集合。
 Public interface IComponent1{
 ReturnType1 method1(arg1, arg2, etc.);
 ReturnType2 method2(arg1,arg2, etc..)
 }
 
 实现此组件的方法如下所示:
 Public class MyComponentImplementation : IComponent1, ISingleInstance
 {
 // any local variables you may have
 ReturnType1 method1(arg1, arg2, etc.)
 {
 .. Method1 implementation
 }
  ReturnType2 method2(arg1,arg2, etc..){
 .. Method2 implementation
 }
 }
 
 可以使用下列配置文件来指定运行时的实现。
 <request name="IComponent1><type>MyComponentImplementation,MyAssembly</type>
 </request>
 
 这里的“type”是.NET用以指定类名的一种机制。一旦上述的配置正确,就可以照此来使用组件:
 Ifactory fact;IComponent1 compInterface = (Icomponent1)fact.getObject
 ("IComponent1");
 compInterface.method1(..);
 compInterface.method2(..);
 
 这些组件的具体优势 首先,这些组件可以保证类型安全。这就是说参数能够使用类型安全的方法来调用组件之上的方法。一旦获得了组件,利用符号名,该组件之上的方法就可以保证类型安全。
 其次,这些组件是独立存在的。您可以根据需要在应用程序中的任一位置申请和使用某一组件。不过,这里有这样一个假定:将组件作为无状态方法集来实现。如果想使用有状态方法,将不能实现 
        ISingleInstance 标记。  (责任编辑 Sunny)  
 
 |