使用特定模式实现接口

Øyv*_*hen 6 .net c# design-patterns interface

最近我一直非常喜欢设计模式,特别是在我的类中遵循正确的设计模式来实现一个或多个接口.

我们来举个例子吧.当一个类实现时,IDisposable你应该遵循一个特定的模式,以确保你的资源被正确清理,通过创建一个私有Dispose(bool disposing)方法来区分它是否被终结器调用,或者是否从公共Dispose方法调用它.此外,在这种情况下应该实现终结器,并且您可能还需要一个名为isDisposed的私有bool变量,该变量由Dispose方法设置,因此在对象之后调用的任何方法都将调用Exception,使其明确该对象已经处置,而不是方法内部的代码崩溃,因为一些必需的资源被处置,从而不再可用.

我还经常实现很多其他接口,但并不是所有接口我确信如果我实现它们的方式是首选的方式,我可能会在稍后发现它会导致一个微妙的错误,即很难找到,如果我首先遵循正确的模式,那可能是不存在的.

接口的一些例子我想知道最好的实现方式是ISerializable,IComparable,IComparable <>,ICloneable,IEnumerable <>等等.框架中的所有接口都很有趣,因此不应局限于上面列出的那些接口.

我所追求的是不同的界面,首选的方式,并希望也是互联网上的资源链接,解释了如何以及为什么应该遵循特定的模式.

我希望能够很好地收集这些模式,因为我知道它们可以极大地改进我的代码并使其更正确,并遵循最佳实践

如果同一界面有多个模式,那将是很好的,因此我们可以讨论哪一个是首选的.这也许会导致你们中的一些人转向新的模式,或者对现有的模式进行修改,以进一步改进你的代码,这将是非常棒的!

编辑

在阅读Grzenios评论之后,我还会敦促每个人都给出应该应用模式的上下文.例如,只有在类中需要处理某些非托管资源时才应遵循IDIsposable模式,而不是如果您需要处置的所有对象都自己实现IDisposable.

编辑2

我应该自己开始,因为我在这里提出这个问题.所以我将描述一种我熟悉的模式,那就是IDisposable模式.

这种模式应仅用于如果你的类包含的类中的一个或多个非托管资源,你甲肝埃托奥确保他们得到弃置.在这种情况下,除了Dispose方法,我们需要一个终结的情况下,你的类的用户忘记处置它.

首先是第一件事.你的类应该实现IDisposable接口,你就必须用接口goverend界定公共Dispose方法.此方法应如下所示:

public void Dispose()
{
  Dispose(true);
  GC.SuppressFinalize(this);
}
Run Code Online (Sandbox Code Playgroud)

这将调用受保护的Dispose(bool)方法来处理实际的清理工作.

此外,在您的班级中加入一个vaiable来表明该班级是否被处置:

private bool alreadyDisposed = false;
Run Code Online (Sandbox Code Playgroud)

GC.SuppressFinalize告诉垃圾收集器,即使它有终结器,也不需要最终确定该项.

然后你需要受保护的Dispose方法.如果任何派生类需要覆盖它,请使其受保护而不是私有:

protected virtual void Dispose(bool isDisposing)
{
  if (alreadyDisposed)
  {
    return;
  }
  if (isDisposing)
  {
    // free all managed resources here
  }
  // free all unmanaged resources here.
  alreadyDisposed = true;
}
Run Code Online (Sandbox Code Playgroud)

如果用户忘记清理,终结器也应该调用Dispose(bool):

~SomeClass(){
  Dispose(false);
}
Run Code Online (Sandbox Code Playgroud)

如果某些方法需要配置资源才能运行,请执行以下功能:

public void SomeMethod()
{
  if (alreadyDisposed)
    throw new ObjectDisposedException("SomeClass",
                                      "Called SomeMethod on Disposed object");
  // Method body goes here
}
Run Code Online (Sandbox Code Playgroud)

而已.这将确保资源得到清理.您的类的用户最好调用Dispose,但添加Finalizer作为后备方法.

Mar*_*k H 3

当您学习设计模式时,您还应该查看一些常见的反模式,您会了解模式的来源。IDisposable在某种程度上是一种反模式,是顺序耦合的次要版本,因为它要求用户调用 dispose,如果他忘记了,你就完蛋了。“一次性模式”的主要原因之一就是解决这个问题。

一种首选技术(无论如何,我的),只要有可能,就是不向用户公开 IDisposable 对象,而是公开一个方法(Using(...)例如调用它),该方法采用一个委托,该委托将执行通常包含在using(...) { }块中的代码。该方法可以执行您的构造,执行委托,然后处理它消耗的资源,并忽略 IDisposable 的至少 3 个问题:用户忘记调用它、用户多次调用它以及用户也调用它早期 - 当没有 IDisposable 暴露时,您不需要担心样板“一次性模式”。

举个例子,假设我有一个文件 IO 要求,我需要定期打开相同的文件(因此,如果用户忘记调用 Dispose,我不能等待垃圾收集器调用 Finalize)。

class MyFileStream {
    FileStream fs;
    private MyFileStream(string filename, FileMode mode) {
        fs = new FileStream(filename, FileMode.Open);
    }
    private void Dispose() {
        fs.Dispose();
    }
    public static void Using(string filename, FileMode mode, Action<MyFileStream> use) {
        MyFileStream mfs = new MyFileStream(filename, mode);
        use(mfs);
        mfs.Dispose();
    }
    public void Read(...) { ... }
}
Run Code Online (Sandbox Code Playgroud)

然后呼叫者可以说

var x = default(...);
MyFileStream.Using("filename.txt", FileMode.Open, (stream) => {
    x = stream.Read(...);
});
Console.WriteLine(x);
Run Code Online (Sandbox Code Playgroud)

请注意,无论如何,这与语言语法非常相似using() { },只是这一次您被迫使用它,并且它施加了进一步的限制。人们不能忘记以这种方式清理资源。

不过,这种模式并不总是合适,因为有时您需要的资源比仅仅方法调用的持续时间更长,但如果您找到使用它的机会,请这样做。

无论如何,我完全偏离了主题,所以回到你问的问题。

  • 不要使用 ICloneable - 它没有说明如何克隆对象(深克隆或浅克隆),如果您需要这样的东西,请创建您自己的 IDeepCloneable 或 IShallowCloneable 接口。
  • 对于 IEnumerable<>,很少需要您创建自己的类,因为框架中已有相当大的现有类集合,并且您通常可以通过实现扩展方法(例如LINQ,或您自己的,使用强大的yield关键字,这将在后台为您创建一个 IEnumerable<>)。

我不会说其余的有任何特定的模式,它们是不言自明的。