我不同意你的结论。有很多很好的方法可以将上述所有技术封装在 c# 中,以保持良好的软件编码实践。我还要说这取决于您正在查看谁的技术演示,但最终归结为减少对象的状态空间,以便您可以确保它们始终保持其不变量。
以对象关系框架为例;它们中的大多数允许您指定它们将如何水合实体;例如 NHibernate 允许你这么说access="property"
或access="field.camelcase"
类似的。这允许您封装您的属性。
依赖注入适用于您拥有的其他类型,主要是那些不是实体的类型,即使您可以以一些非常好的方式结合 AOP+ORM+IOC 来改善这些事物的状态。如果你正在构建一个数据驱动的应用程序,我猜你就是这样,因为你在谈论 ORM,所以 IoC 通常用于域实体之上的层。
它们(“它们”是应用程序和域服务以及程序的其他内在类)暴露了它们的依赖关系,但实际上可以在比以前更好的隔离中封装和测试,因为按合同设计/按接口设计的范例您在基于模拟的测试(与 IoC 结合)中模拟依赖项时经常使用它,这将使您转向类即组件“语义”。我的意思是:每个类,当使用上述构建时,将被更好地封装。
为 urig 更新:这对于公开具体依赖项都适用并暴露接口。首先关于接口:我上面暗示的是,服务和其他具有依赖关系的应用程序类可以使用 OOP 依赖于契约/接口而不是特定的实现。在 C/C++ 和更早的语言中,没有接口,抽象类只能走这么远。接口允许您将不同的运行时实例绑定到同一个接口,而不必担心泄漏内部状态,这是您在抽象和封装时试图摆脱的。使用抽象类你仍然可以提供一个类实现,只是你不能实例化它,但是继承者仍然需要知道你的实现中的不变量,这可能会弄乱状态。
其次,关于作为属性的具体类:您必须警惕哪些类型的类型;)您作为属性公开。假设您的实例中有一个列表;然后不要将 IList 公开为属性;这可能会泄漏,您不能保证界面的使用者不会添加或删除您所依赖的东西;而是公开 IEnumerable 之类的内容并返回 List 的副本,或者更好的是,将其作为方法执行: public IEnumerable MyCollection { get { return _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% 的封装,但您可以接近您的公共接口。
您还可以使用基于 Spec# 构建的 .Net 4.0 的新功能来验证我上面谈到的合约。
序列化将永远存在并且已经存在了很长时间。以前,在 Internet 区域之前,它用于将对象图保存到磁盘以供以后检索,现在它用于 Web 服务、复制语义以及将数据传递到例如浏览器时。如果您将一些 [NonSerialized] 属性或等效项放在正确的字段上,这不一定会破坏封装。
对象初始化器与构造器不同,它们只是折叠几行代码的一种方式。{} 中的值/实例在所有构造函数都运行之前不会被分配,因此原则上它与不使用对象初始化器相同。
我想,你需要注意的是偏离了你从以前的工作中学到的好的原则,并确保你的领域对象充满了封装在良好接口后面的业务逻辑,并且同样适用于你的服务层。