框架时代的封装 [英] Encapsulation in the age of frameworks

查看:198
本文介绍了框架时代的封装的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的旧C ++工作中,我们始终非常小心地封装成员变量,并且只有在绝对必要时才将它们作为属性公开。

At my old C++ job, we always took great care in encapsulating member variables, and only exposing them as properties when absolutely necessary. We'd have really specific constructors that made sure you fully constructed the object before using it.

现在,使用ORM框架,依赖注入,序列化等等,看起来你最好只是依靠默认构造函数,并在属性中暴露你的类的所有内容,这样你就可以注入事物,或者更动态地构建和填充对象。

These days, with ORM frameworks, dependency-injection, serialization, etc., it seems like you're better off just relying on the default constructor and exposing everything about your class in properties, so that you can inject things, or build and populate objects more dynamically.

在C#中,使用Object初始化器进一步了,这使得你能够基本定义自己的构造函数。 (我知道对象初始化器不是真正的自定义构造函数,但我希望你能得到我的观点。)

In C#, it's been taken one step further with Object initializers, which give you the ability to basically define your own constructor. (I know object initializers are not really custom constructors, but I hope you get my point.)

这个方向有什么一般的问题吗?看起来封装开始变得不那么重要,为了方便。

Are there any general concerns with this direction? It seems like encapsulation is starting to become less important in favor of convenience.

编辑:我知道你仍然可以仔细封装成员,但我只是觉得,当你试图找出一些类,你必须坐下来仔细想想如何封装每个成员,或者只是将它暴露为一个属性,并担心如何初始化它。它似乎是最简单的方法,这些天是暴露的东西作为属性,而不是那么小心。也许我只是一个错误,但这只是我的经验,特别是与新的C#语言功能。

I know you can still carefully encapsulate members, but I just feel like when you're trying to crank out some classes, you either have to sit and carefully think about how to encapsulate each member, or just expose it as a property, and worry about how it is initialized later. It just seems like the easiest approach these days is to expose things as properties, and not be so careful. Maybe I'm just flat wrong, but that's just been my experience, espeically with the new C# language features.

推荐答案

与你的结论。有许多好的方法在c#中封装所有上述技术,以保持良好的软件编码实践。我还会说,这取决于他们的技术演示,你看,但最终,它归结为减少对象的状态空间,以便你可以确保他们随时保持不变量。

I disagree with your conclusion. There are many good ways of encapsulating in c# with all the above mentioned technologies, as to maintain good software coding practices. I would also say that it depends on whose technology demo you're looking at, but in the end it comes down to reducing the state-space of your objects so that you can make sure they hold their invariants at all times.

使用对象关系框架;大多数允许你指定他们如何水合实体;例如,NHibernate允许你这样说 access =property access =field.camelcase

Take object relational frameworks; most of them allow you to specify how they are going to hydrate the entities; NHibernate for example allows you so say access="property" or access="field.camelcase" and similar. This allows you to encapsulate your properties.

依赖注入适用于您拥有的其他类型,大多数不是实体的类型,即使您可以组合AOP + ORM + IOC在一些非常好的方式来提高这些东西的状态。如果你正在构建一个数据驱动的应用程序,我猜你是,因为你在谈论ORMs,IoC通常从你的域实体上面的层使用。

Dependency injection works on the other types you have, mostly those which are not entities, even though you can combine AOP+ORM+IOC in some very nice ways to improve the state of these things. IoC is often used from layers above your domain entities if you're building a data-driven application, which I guess you are, since you're talking about ORMs.

他们(他们是应用程序和域服务以及程序的其他内在类)暴露了它们的依赖,但实际上可以被封装和测试,因为在基于模拟测试(与IoC相结合)中嘲笑依赖关系时经常使用的按合同设计或按接口设计的范例将使您转向类作为组件的语义。

They ("they" being application and domain services and other intrinsic classes to the program) expose their dependencies but in fact can be encapsulated and tested in even better isolation than previously since the paradigms of design-by-contract/design-by-interface which you often use when mocking dependencies in mock-based testing (in conjunction with IoC), will move you towards class-as-component "semantics". I mean: every class, when built using the above, will be better encapsulated.

为urig更新:这对于暴露混凝土都是适用的依赖关系和展示界面。首先关于接口:我在上面暗示的是,服务和其他应用程序类有依赖性,可以与OOP依赖于契约/接口,而不是具体的实现。在C / C ++和较旧的语言中,没有接口和抽象类只能走得那么远。接口允许你将不同的运行时实例绑定到同一个接口,而不必担心泄漏的内部状态,这是你在抽象和封装时想逃避的。使用抽象类,你仍然可以提供一个类实现,只是你不能实例化它,但是继承者仍然需要知道你的实现中的不变量,并且可以弄乱状态。

Updated for urig: This holds true for both exposing concrete dependencies and exposing interfaces. First about interfaces: What I was hinting at above was that services and other applications classes which have dependencies, can with OOP depend on contracts/interfaces rather than specific implementations. In C/C++ and older languages there wasn't the interface and abstract classes can only go so far. Interfaces allow you to tie different runtime instances to the same interface without having to worry about leaking internal state which is what you're trying to get away from when abstracting and encapsulating. With abstract classes you can still provide a class implementation, just that you can't instantiate it, but inheritors still need to know about the invariants in your implementation and that can mess up state.

其次,关于具体类作为属性:你必须警惕什么类型的类型;)你公开为属性。假设您的实例中有一个列表;那么不要暴露IList作为属性;这可能会泄漏,你不能保证接口的消费者不添加东西或删除你依赖的东西;而是暴露类似IEnumerable的东西,并返回一个List的副本,或者更好,做一个方法:
public IEnumerable MyCollection {get {return _List.Enum(); }},你可以100%确定获得性能和封装。没有人可以添加或删除到IEnumerable,你仍然不必执行昂贵的阵列副本。相应的辅助方法:

Secondly, about concrete classes as properties: you have to be wary about what types of types ;) you expose as properties. Say you have a List in your instance; then don't expose IList as the property; this will probably leak and you can't guarantee that consumers of the interface don't add things or remove things which you depend on; instead expose something like IEnumerable and return a copy of the List, or even better, do it as a method: public IEnumerable MyCollection { get { return _List.Enum(); } } and you can be 100% certain to get both the performance and the encapsulation. Noone can add or remove to that IEnumerable and you still don't have to perform a costly array copy. The corresponding helper method:

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

所以当你无法获得100%封装

So while you can't get 100% encapsulation in say creating overloaded equals operators/method you can get close with your public interfaces.

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

You can also use the new features of .Net 4.0 built on Spec# to verify the contracts I talked about above.

序列化将永远存在,已经有很长时间了。以前,在互联网区域之前,它用于将对象图保存到磁盘以供稍后检索,现在它用于Web服务,复制语义以及将数据传递到浏览器。这不一定破坏封装,如果你把几个[NonSerialized]属性或等价的正确的字段。

Serialization will always be there and has been for a long time. Previously, before the internet-area it was used for saving your object graph to disk for later retrieval, now it's used in web services, in copy-semantics and when passing data to e.g. a browser. This doesn't necessarily break encapsulation if you put a few [NonSerialized] attributes or the equivalents on the correct fields.

对象初始化不同于构造函数,他们只是一种折叠几行代码的方法。在所有的构造函数都运行之前,{}中的值/实例将不会被赋值,所以原则上它与没有使用对象初始化器一样。

Object initializers aren't the same as constructors, they are just a way of collapsing a few lines of code. Values/instances in the {} will not be assigned until all of your constructors have run, so in principle it's just the same as not using object initializers.

你必须注意的是偏离了你从你以前的工作中学到的好原则,并确保你保持你的域对象填充业务逻辑封装好的接口和同上为您的服务层。

I guess, what you have to watch out for is deviating from the good principles you've learnt from your previous job and make sure you are keeping your domain objects filled with business logic encapsulated behind good interfaces and ditto for your service-layer.

这篇关于框架时代的封装的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆