Windsor:如何处理使用基于接口的类型工厂创建的对象

时间:2012-01-21 11:02:06

标签: dependency-injection inversion-of-control castle-windsor ioc-container

我开始使用Windsor,发现了非常非常酷的功能:打字工厂。我了解到每当我使用工厂获取实例时,我也不得不要求它在我不需要时销毁实例。我想知道这是如何适用于一个非常常见的操作,如在磁盘上打开文件。模特:

interface IDisk
  IFile OpenFile(string path)
interface IFileFactory
  IFile Create(string path)
  void Destroy(IFile openFile)
interface IFile // empty, it's not important what it does

class Disk : IDisk
  ctor(IFileFactory fileFactory)
  IFile OpenFile(string path)
     return fileFactory.Create(path)

用户代码:

disk = container.Resolve<IDisk>() // disk is root so this is not SL
file = disk.OpenFile("foo.bar");
// do something with file

现在是摆脱文件的时候了。普通的.NET用户会调用file.Dispose()。但这次事情有所不同:

  • 该文件是一个不继承IDisposable的接口(如果它确实那么它将是一个漏洞的抽象);但是File类实现了IDisposable
  • 该文件由拥有它的工厂创建

所以这是另一种方式:代替DisposeIFile接口有一个额外的方法Close,它应该从工厂释放文件实例,而工厂又调用{{} 1 {}在Dispose实例上。要使其工作,File类必须要知道文件工厂(我不喜欢)或其File方法:

Destroy

我也不喜欢这个...如果我更改模型以使文件不会自行关闭,但磁盘会关闭文件,我可以避免所有这些麻烦:

class File : IFile
  ctor(Action<IFile> destroyCallback)

对于撰写//file.Close() // not supported, by design disk.Close(file) Disk课程的人来说,这更容易,但我担心我的用户不会欣赏这种“新模式”。

思想?

1 个答案:

答案 0 :(得分:2)

好的,让我按顺序解决这个问题:

  

普通的.NET用户会调用file.Dispose()。

无论您是否使用容器,调用file.Dispose()都是错误的。 .NET中的规则是你不应该破坏你没有创建的东西。

这适用于.Dispose()以及ctor(Action<IFile> destroyCallback)

那么谁拥有文件?就你的代码而言,工厂确实如此。因此,工厂有责任在文件后进行清理。

如果您将工厂保留为Disk的实施细节(您最有可能),那么Disk是您的表面区域API,用于打开并关闭 文件因此它需要一个Close(IFile file)方法,当实现细节将其传递给工厂时。

因此该文件的用法如下所示:

var myfile = disk.OpenFile(@"c:\myfile.txt);
try
{
   DoSomethingWithTheFile(myFile);
}
finally
{
   disk.Close(myFile);
}

[编辑:基于评论]

好吧,如果你期望,并希望你的用户有一些IDisposable对象,然后给他们一个(我宁愿反对这个,但这不是我的电话)

OpenFile方法将返回如下所示的对象:

public class FileScope:IDisposable
{
   private Action<IFile> close;

   public FileScope(IFile file, Action<IFile> close)
   {
      File = file;
      this.close = close;
   }


   public IFile File {get; private set;}

   public void Dispose()
   {
      close(file);
   }
}

关闭代表将回调disk.Close,如

public FileScope OpenFile(string path)
{
   return new FileScope(fileFactory.Create(path),Close);
}