-NET-Core3-设计模式教程-六-

27 阅读6分钟

.NET Core3 设计模式教程(六)

原文:Design Patterns in .NET Core 3

协议:CC BY-NC-SA 4.0

第一部分:介绍

第二部分:创建模式

Creational Patterns

在像 C# 这样的“托管”语言中,创建一个新对象的过程很简单:只需new它并忘记它。嗯,有stackalloc,但是我们主要说的是需要持久化的对象。现在,随着依赖注入的扩散,另一个问题是手动创建对象是否仍然是可接受的,或者我们是否应该将基础设施的所有关键方面的创建推迟到专门的构造,例如工厂(稍后将详细介绍它们!)还是控制容器的倒置?

无论您选择哪一个选项,创建对象仍然是一件苦差事,尤其是如果构建过程很复杂或者需要遵守特殊的规则。这就是创造模式的用武之地:它们是与创建对象相关的常见方法。

万一您对 C# 中构造对象的方法感到生疏,让我们回顾一下主要的方法:

  • 调用new在托管堆上创建一个对象。对象不需要被显式销毁,因为垃圾收集器(GC)会替我们处理它。

  • 使用stackalloc的堆栈分配在堆栈上而不是堆上分配内存。堆栈分配的对象只存在于它们被创建的范围内,当它们超出范围时会被自动清除。此构造只能用于值类型。

  • 您可以用Marshal.AllocHGlobalCo-TaskMemAlloc分配非托管(本机)内存,并且必须用Marshal.FreeHGlobalCoTaskMem-Free显式释放它。这主要是与非托管代码进行互操作所需要的。

不用说,一些托管组件可能在幕后使用非托管内存。这也是IDisposable接口存在的主要原因之一。这个接口只有一个方法Dispose(),它可以包含清理逻辑。如果你正在处理一个实现了IDisposable的对象,将它的使用封装在一个using语句中(我们现在也有了using var)可能是有意义的,这样一旦不再需要这个对象,它的清理代码就会被执行。

第三部分:结构模式

Structural Patterns

顾名思义,结构模式就是建立应用的结构,从而提高代码的一致性以及可用性和可维护性。

当涉及到确定物体的结构时,我们可以应用这些相当众所周知的方法:

  • 继承:一个对象自动获取所有成员的基类。为了允许实例化,对象必须实现来自其父对象的每个抽象成员;如果没有,那它就是抽象的,不能被创造(但是你可以从中继承)。

  • 构成:一般暗示孩子离开父母就无法存在。这通常是用嵌套类实现的。例如,一个类Car可以有一个嵌套类Wheel

  • 聚合:一个对象可以包含另一个对象,但是那个对象也可以独立存在。假设一个Car有一个Person driver字段或属性。

如今,组合和聚合都以相同的方式处理。如果你有一个字段类型为AddressPerson类,你可以选择Address是外部类型还是嵌套类型。在这两种情况下,只要它是public,就可以将其实例化为AddressPerson.Address

我认为,当我们真正指的是聚合时,使用单词 composition 已经变得如此普遍,以至于我们也可以以可互换的方式使用它们。这里有一些证据:当我们谈到 IoC 容器时,我们谈到一个组合根。但是等等,IoC 容器不是单独控制每个对象的生存期吗?确实如此,所以当我们真正指“聚合”时,我们使用“组合”这个词

基本上,在 C# 中有三种定义数据结构的方法:

  • 静态地:当你简单地编写类,然后它们被编译。这是最常见的情况。

  • 通过代码生成:当从 ?? 模板或数据库或一些用户脚本中创建结构时,就会发生这种情况。例如,在 WinForms 或 Windows Presentation Foundation(WPF)应用中编辑用户界面时,会在后台生成大量代码。

  • 动态,也就是运行时:这是最复杂的选项。高级库能够构建数据结构,并在应用执行的那一刻将它们编译成可执行代码。这种方法有时在设计模式中被利用,并导致它们的静态-动态二元性。

值得注意的是,许多数据结构是由编译器在幕后隐式创建的。这包括像ValueTuple这样的东西,匿名类型的类,以及负责编排枚举器(yield功能)或异步(async/await)操作的状态机。

在 F# 中,在后台创建的数据结构(和相应的分配)的数量是巨大的,这些数据结构的复杂性也是如此。例如,任何类型的 currying 操作都会产生深层次的继承。或者,让我们说,您决定将一个操作符(如(+))作为参数传递给一个函数——在这种情况下,将创建一个完整的struct,纯粹是为了存放一个调用该操作符的方法。如果认为所有这样的分配在 JIT 编译期间都是自动内联的,那就太天真了!

第四部分:行为模式

Behavioral Patterns

当大多数人听说行为模式时,主要是与动物有关,以及如何让它们做你想做的事情。嗯,在某种程度上,所有的编码都是关于程序做你想做的事情,所以行为软件设计模式涵盖了非常广泛的行为,尽管如此,这些行为在编程中还是很常见的。

作为一个例子,考虑软件工程领域。我们有经过编译的语言,其中包括词法分析、语法分析和数以百万计的其他事情(解释器模式),并且已经为一个程序构建了一个抽象语法树(AST),您可能想要分析程序中可能存在的错误(访问者模式)。所有这些行为都很常见,可以用模式来表达,这就是我们今天在这里的原因。

与创造模式(专门关注对象的创建)或结构模式(关注对象的组合/聚合/继承)不同,行为设计模式不遵循一个中心主题。虽然不同的模式之间有某些相似之处(例如,策略和模板方法以不同的方式做同样的事情),但是大多数模式都提供了解决特定问题的独特方法。