gpt4 book ai didi

frameworks - 框架时代的封装

转载 作者:行者123 更新时间:2023-12-04 12:38:40 25 4
gpt4 key购买 nike

在我以前的 C++ 工作中,我们总是非常小心地封装成员变量,并且只在绝对必要时才将它们作为属性公开。我们有非常具体的构造函数来确保你在使用它之前完全构造了对象。

如今,使用 ORM 框架、依赖注入(inject)、序列化等,似乎您最好只依赖默认构造函数并在属性中公开有关您的类的所有内容,以便您可以注入(inject)内容,或构建和填充对象更动态。

在 C# 中,对象初始值设定项更进一步,它使您能够基本上定义自己的构造函数。 (我知道对象初始值设定项并不是真正的自定义构造函数,但我希望你明白我的意思。)

这个方向是否有任何普遍的担忧?封装似乎开始变得不那么重要,而有利于便利。

编辑:我知道您仍然可以仔细封装成员,但我只是觉得当您尝试创建某些类时,您要么必须坐下来仔细考虑如何封装每个成员,或者只是将其作为属性公开,并担心它稍后如何初始化。现在似乎最简单的方法是将事物作为属性公开,而不是那么小心。也许我完全错了,但这只是我的经验,尤其是新的 C# 语言功能。

最佳答案

我不同意你的结论。有许多很好的方法可以将上述所有技术封装在 c# 中,以保持良好的软件编码实践。我还要说这取决于您正在查看谁的技术演示,但最终归结为减少对象的状态空间,以便您可以确保它们始终保持不变。

对象关系框架 ;它们中的大多数允许您指定它们将如何水合实体;例如,NHibernate 允许您这样说 access="property"access="field.camelcase"和类似的。这允许您封装您的属性。

依赖注入(inject) 适用于您拥有的其他类型,主要是那些不是实体的类型,即使您可以以一些非常好的方式组合 AOP+ORM+IOC 来改善这些事物的状态。如果您正在构建一个数据驱动的应用程序,IoC 通常在域实体之上的层使用,我猜您是这样,因为您在谈论 ORM。

它们(“它们”是应用程序和域服务以及程序的其他内在类)暴露了它们的依赖关系,但实际上可以在比以前更好的隔离下进行封装和测试,因为按契约(Contract)设计/按接口(interface)设计的范式在基于模拟的测试(与 IoC 结合)中模拟依赖项时,您经常使用它,它将使您转向类作为组件的“语义”。我的意思是:每一个类,当使用上述方法构建时,都会被更好地封装。

为 urig 更新:这适用于暴露混凝土 依赖项 并暴露接口(interface)。首先关于接口(interface):我在上面暗示的是具有依赖关系的服务和其他应用程序类可以与 OOP 依赖于契约(Contract)/接口(interface)而不是特定的实现。在 C/C++ 和较旧的语言中,没有接口(interface),抽象类只能到此为止。接口(interface)允许您将不同的运行时实例绑定(bind)到同一个接口(interface),而不必担心泄漏内部状态,这是您在抽象和封装时试图摆脱的。使用抽象类,您仍然可以提供类实现,只是您无法实例化它,但是继承者仍然需要了解您的实现中的不变量,这可能会弄乱状态。

其次,关于作为属性的具体类:您必须警惕什么类型的类型 ;) 作为属性公开。假设您的实例中有一个 List;然后不要将 IList 作为属性公开;这可能会泄漏,您不能保证接口(interface)的使用者不会添加或删除您依赖的东西;而是公开诸如 IEnumerable 之类的内容并返回 List 的副本,或者甚至更好,将其作为方法执行:
公共(public) IEnumerable MyCollection { 获取 { 返回 _List.Enum();并且您可以 100% 确定同时获得性能和封装。没有人可以添加或删除该 IEnumerable,您仍然不必执行昂贵的数组复制。对应的辅助方法:

static class Ext {
public static IEnumerable<T> Enum<T>(this IEnumerable<T> inner) {
foreach (var item in inner) yield return item;
}
}

因此,虽然在创建重载等于运算符/方法方面无法获得 100% 的封装,但您可以接近公共(public)接口(interface)。

您还可以使用基于 Spec# 构建的 .Net 4.0 的新功能来验证我上面谈到的合约。

序列化将永远在那里并且已经存在了很长时间。以前,在互联网领域之前,它用于将您的对象图保存到磁盘以供以后检索,现在它用于 Web 服务、复制语义以及将数据传递给例如浏览器。如果您在正确的字段上放置了一些 [NonSerialized] 属性或等效项,这不一定会破坏封装。

对象初始值设定项与构造函数不同,它们只是折叠几行代码的一种方式。 {} 中的值/实例在您的所有构造函数都运行之前不会被分配,因此原则上它与不使用对象初始值设定项相同。

我想,您必须注意的是偏离了您从以前的工作中学到的良好原则,并确保您的域对象充满了封装在良好接口(interface)后面的业务逻辑,并且服务层也是如此。

关于frameworks - 框架时代的封装,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/559953/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com