c# - 使用特定的模式来实现接口(interface)

标签 c# .net design-patterns interface

最近,我对设计模式非常感兴趣,尤其是在实现一个或多个接口(interface)的类中遵循正确的设计模式。

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

我还会例行实现很多其他接口(interface),但是我不确定不是所有这些接口(interface)都可以实现,因为我可以确定实现它们的方式是否是首选方式,稍后我可能会发现它会导致一个细微的错误,即很难找到,如果我一开始就遵循正确的模式,那可能就不存在了。

我想知道最佳实现方式的一些接口(interface)示例是ISerializable,IComparable,IComparable <>,ICloneable,IEnumerable <>等。框架中的所有接口(interface)在这里都很有趣,因此它不应该局限于我上面列出的那些接口(interface)。

我所追求的是针对不同的界面,首选的方式以及希望与互联网上资源的链接,该链接说明了如何以及为什么应遵循特定的模式。

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

如果同一接口(interface)有多种模式,那就太好了,因此我们可以讨论哪种模式是更可取的。这也可能导致你们中的一些人转向新的模式,或者对您现有的模式进行修改以进一步改善代码,那就太好了!

编辑

在阅读了Grzenios的评论之后,我还敦促每个人提供应该应用该模式的上下文。例如,仅当您的类中有一些需要处理的非托管资源时才应遵循IDIsposable模式,而不是如果需要处理的所有对象本身都实现了IDisposable则不应该遵循IDIsposable模式。

编辑2

我可能应该自己开始,因为我在这里提出了问题。因此,我将描述一种我很熟悉的模式,那就是IDisposable模式。

仅当您的类在您的类中包含一个或多个非托管资源并且您必须确保将其分配为Dispose时,才应使用此模式。在这种情况下,除了Dispose方法外,我们还需要一个终结器,以防您的类的用户忘记处理它。

所以第一件事。您的类应实现IDisposable接口(interface),并且您必须通过该接口(interface)将公共(public)Dispose方法定义为goverend。此方法应如下所示:

public void Dispose()
{
  Dispose(true);
  GC.SuppressFinalize(this);
}

这将调用 protected Dispose(bool)方法,该方法负责实际的清理。

另外,在类(class)中加入一个空缺职位,以表明该类(class)是否被处置:
private bool alreadyDisposed = false;

GC.SuppressFinalize告诉垃圾收集器即使有终结器也不需要终结该项目。

然后,您需要 protected Dispose方法。在任何派生类需要覆盖它的情况下,将其设置为保护而不是私有(private):
protected virtual void Dispose(bool isDisposing)
{
  if (alreadyDisposed)
  {
    return;
  }
  if (isDisposing)
  {
    // free all managed resources here
  }
  // free all unmanaged resources here.
  alreadyDisposed = true;
}

如果用户忘记清理,则终结器还应调用Dispose(bool):
~SomeClass(){
  Dispose(false);
}

如果某些方法需要已分配的资源才能运行,请执行以下功能:
public void SomeMethod()
{
  if (alreadyDisposed)
    throw new ObjectDisposedException("SomeClass",
                                      "Called SomeMethod on Disposed object");
  // Method body goes here
}

就是这样。这将确保清理资源。类的用户最好调用Dispose,但可以通过添加Finalizer作为后备方法。

最佳答案

在学习设计模式时,您还应该查看一些常见的反模式,从而了解模式的来源。 IDisposable有点像反模式,是sequential coupling的次要版本,因为它要求用户调用dispose,如果他忘了,那您就大为the幸了。 “一次性模式”的主要原因之一就是要解决此问题。

无论如何,首选的技术(无论如何)不是将IDisposable对象公开给用户,而是公开一个方法(例如,称为Using(...)),该方法采用一个委托(delegate),该委托(delegate)将执行通常包含在using(...) { }中的代码堵塞。此方法可以执行构造,执行委托(delegate),然后处理消耗的资源,并至少消除IDisposable的3个问题:用户忘记调用它,用户多次调用它以及用户也调用它的问题。尽早-当没有IDisposable暴露时,您无需为该样板“disposable pattern”烦恼。

举个例子,假设我有一个文件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(...) { ... }
}

然后调用者可以说
var x = default(...);
MyFileStream.Using("filename.txt", FileMode.Open, (stream) => {
    x = stream.Read(...);
});
Console.WriteLine(x);

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

但是,这种模式并不总是合适的,因为有时您需要的资源的持续时间可能不止一个方法调用左右,但是如果您发现使用它的机会,请这样做。

无论如何,我已经完全摆脱了话题,回到您的要求。
  • 不要使用ICloneable-它没有说明如何克隆对象(深层或浅层),如果需要,请创建自己的IDeepCloneable或IShallowCloneable接口(interface)。
  • 对于IEnumerable <>,这是一个罕见的事件,您需要创建自己的事件,因为框架中已经存在相当大的现有类集合,并且通常可以通过实现扩展方法来更简单地获得其他功能(例如在LINQ(或您自己的)中使用强大的yield关键字,它将在后台为您创建IEnumerable <>。

  • 我不会说其余的任何特定模式,它们很容易解释。

    关于c# - 使用特定的模式来实现接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3708306/

    相关文章:

    .net - 如何打开选择了特定文件夹的 Windows 资源管理器窗口

    c# - 将数据从控制台应用程序发送到 asp.net 网站

    C++ "triangle"(而不是菱形)继承

    c# iOS 10 通知 - GetDictionaryOfValuesFromKeys() 错误

    c# - 使用三元运算符 : "only assignment, call, increment..."

    c# - 使用 OR 条件断言

    c# - 关于基于ServiceStack的服务类型命名的问题

    c# - 程序集 "Microsoft.GeneratedCode"已加载

    c# - 必须在业务层注入(inject)规范?

    c++ - 递归模板成语如何避免基类是子类的 friend