干净的代码:对象应该具有公共属性吗?
我正在读《干净的代码》一书,并且正在为一个概念而苦苦挣扎。在讨论对象和数据结构时,它指出了以下内容:
- 对象将其数据隐藏在抽象后面,并公开对该数据进行操作的函数。
- 数据结构公开其数据并且没有有意义的功能。
因此,我从中得到的是,我的对象上不应该有任何公共属性,我应该只具有对属性执行操作的方法。如果我确实需要访问属性,它们应该位于数据结构上,可以从我的对象上的方法返回?通过这种方法,我似乎需要为对象上的 Height 属性提供 GetHeight() 和 SetHeight() 方法,而不仅仅是使用对象的 get 和 set财产。
也许我不完全理解所建议的内容,但这是我对“对象隐藏其数据”的理解。如果您能帮助我理解这一点,我将不胜感激!
提前致谢!
I'm reading the book "Clean Code" and am struggling with a concept. When discussing Objects and Data Structures, it states the following:
- Objects hide their data behind abstractions and expose functions that operate on that data.
- Data Structures expose their data and have no meaningful functions.
So, what I'm getting from this is that I shouldn't have any public properties on my object, I should only have methods that perform operations on the properties. If I do need to access properties, they should be on a Data Structure, which could be returned from a method on my object? With this approach, it seems that I would need a GetHeight() and SetHeight() method for my Height property on my object, rather than just using get and set of the property.
Maybe I'm not understanding exactly what is being suggested, but this is my understanding of "Objects hide their data." If you could help me understand this, I'd greatly appreciate it!
Thanks in advance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
事实上,C# 属性不是数据,而是访问器,因此它是对数据进行操作的函数。
您应该避免公共字段,而不是公共财产。
Indeed a C# property is not data, is an accessor, so it's a function operating on data.
You should avoid public fields, not public properties.
公共财产很好。不必编写显式的
GetHeight()
和SetHeight()
方法,这就是属性的全部内容。 C# 中的属性不是数据;最好将其视为一对 getter/setter 方法。 (属性实际上被编译成生成的 IL 中的方法。)数据隐藏是可能的,因为您可以在不更改接口的情况下更改实现。例如,
则可以更改为
如果您决定对象应始终是正方形, 。使用您的类的代码不需要任何修改。
因此,如果您的对象公开公共属性,它仍然“将其数据隐藏在抽象后面,并公开对该数据进行操作的函数”,正如本书所建议的那样。
Public properties are fine. Not having to write explicit
GetHeight()
andSetHeight()
methods is what properties are all about. A property in C# is not data; it is best viewed as a pair of getter/setter methods. (Properties are actually compiled down into methods in the generated IL.)The data hiding is possible because you can change the implementation without changing the interface. For example, you could change
into
if you decided that your object should always be square. The code using your class would not need any modifications.
So if your object exposes public properties, it still "hides it data behind abstractions and exposes functions that operate on that data", as the book recommends.
它主要是“财产”一词的另一种定义。 C# 中的属性并不是大多数其他语言所认为的属性。
示例:
C++ 公共属性是:
C# 中对应的术语是公共字段:
我们在 C# 中称为属性的内容在其他语言中将是 setter 和 getter:
C#:
对应的 C++:
简而言之:
C# 属性完全没问题,只是不要盲目地默认它们来设置和设置,并且不要将类中的每个数据字段都设置为公共属性,考虑一下类的用户真正需要知道什么/改变。
It is mostly another definition of the term "property". A property in C# is not what most other languages think of as properties.
Example:
A C++ public property is:
The corresponding term in C# would be a public field:
What we name in C# as properties would be setters and getters in other languages:
C#:
corresponding C++:
In short:
C# properties are totally fine, just don't blindly default them to get and set and don't make every datafield in your class a public property, think about what users of your class really need to know/change.
当您读完《清洁代码》后,我建议您阅读 Bob Martin 的另一本书:
在本书中,本书的大部分内容都讨论了案例研究,在其中,Bob 应用了《简洁代码》中讨论的原则。我首先阅读了《清洁代码》,但回想起来,我认为应该首先阅读“敏捷模式..”,因为《清洁代码》更像是一本日常手册或良好软件原则的手册。
例如,在“敏捷模式...”中使用以下代码:
以下对公共数据使用的验证可以解决您的问题:
旁白:就
我个人而言,我不得不说 Robert Martin(与 Martin Fowler、Michael Feathers 一起)通过这些书为软件开发者社区做出了巨大贡献。我认为它们是必读的。
When you are finished Clean Code I would recommend you read Bob Martin's other book:
In this book the vast ammount of the book discusses a case study and in it, Bob applies the principles discussed in Clean Code. I read Clean Code first but in retrospect I think "Agile Patterns.." should be read first as Clean Code is more of a day to day handbook or manual of good SW principles.
For example, in "Agile patterns..." the following code is used:
The following validation of the use of Public data deals with your question:
Aside:
Personally, I have to say that Robert Martin has made a massive contribution to the SW developer community (along with Martin Fowler, Michael Feathers..) with these books. I think they are must read.
虽然公共属性不会立即产生代码味道,但请考虑这篇文章:
Yechiel 的《Coding with Reason》 Kimchi(摘自每个程序员应该知道的 97 件事一书)
“...不要向对象询问要使用的信息。相反,要求对象使用它已经拥有的信息。”
这并不总是起作用(例如,数据传输对象)。我要注意的是不适当的亲密关系。
While public properties are not an immediate code smell, consider this article:
Coding with Reason by Yechiel Kimchi (from the book 97 Things Every Programmer Should Know)
"...don't ask an object for information to work with. Instead, ask the object to do the work with the information it already has."
This doesn't come into play all the time (for example, Data Transfer Objects). What I watch out for is Inappropriate Intimacy.
属性实际上是方法。
编译器编译属性以获取/设置 MIL 方法。
Properties are in fact methods.
The compiler compiles properties to get/set MIL methods.
属性本质上是 Getter 和 Setter 方法的简写。 Getter 和 Setter 方法的要点是让对象处理对变量的任何操作,以便您可以执行任何额外的操作(例如数据验证),而不会造成不良后果。
我认为您可能会沉迷于自动属性,这些属性没有支持变量,因此看起来像变量本身。
Properties are essentially short hand for Getter and Setter methods. The point of Getter and Setter methods is to have the object handle any operations on variables so that you can do any extra operations (such as data-validation) without causing undesirably consequences.
I think that you may be hung up on automatic properties, which have no backing variables and, as a result, look like variables themselves.
这本书试图描述这样一个理论:对象不应该暴露类的实际实现方式。在更复杂的对象中,许多内部变量不一定从外部角度传达正确的信息,而应该只具有作用于它们的方法。
然而,当您拥有简单的对象时,将其作为硬性规则就会失效。对于矩形,高度和宽度是用户想要知道的基本属性。由于其实现非常简单,因此不使用 get 和 set 只会使代码变得比需要的更加复杂。
The book is trying describe the theory that an object should not expose how the class is actually implemented. In more complicated objects many of the internal variables don't necessarily convey the right information from an outside perspective and should just have methods that act on them.
However, making this a hard and fast rule falls apart when you have simple objects. In the case of a rectangle, height and width are basic properties that the user will want to know. And since the implementation of this is straight forward, not using get and set will just make your code more complicated than it needs to be.
事情是这样的。
尽管公共变量有时可能有用,但通常最好将它们保持为私有。
如果对象是唯一可以控制其变量的对象,那么保持代码的组织性就很容易。
想象一下,您想要将高度保持在 0 到 200 之间。如果您有一种方法来设置高度,则可以轻松监控。
例如(为了速度,我将使用 Java):
正如您所看到的,这种方法非常结构化和可控。
现在想象一下,我们有一行代码可以在外部编辑此高度,因为您选择将其公开。除非您在代码之外控制它,否则您可能会得到一个与您的程序表现不佳的高度。即使您确实想要控制它,您也会重复代码。
非常基本的例子,但我认为它很能说明问题。
Here's the deal.
Although public variables may be useful on occasion, it is often best to keep them private.
It's easy to keep your code organized if the object is the only one with control over its variable.
Imagine that you want to maintain a height between 0 and 200. If you have a method to set your height, you can monitor this easily.
For example (I'll be using Java for speed sake):
As you can see, this approach is very structured and controlled.
Now imagine that we have a line of code that edits this height externally because you choose to make it public. Unless you control it outside the code, you may get a height that doesn't behave well with your program. Even if you did want to control it, you'd be repeating code.
Very basic example, but I think it gets the point across.
在纯面向对象中,“真实的对象”必须完全隐藏它用来履行其职责的数据。因此,必须避免暴露内部数据,无论这是由公共字段、公共属性还是公共 getter/setter 函数完成的。
仅通过属性路由访问内部数据既不是隐藏的也不是抽象的!
回答你的问题:
- 如果您正在编写对象,请避免使用公共属性
- 如果您正在编写数据结构,请使用公共属性(公共字段也可以完成这项工作)
In pure OO "a real object" has to completely hide the data it uses to fulfill its responsibility. So exposing internal data has to be avoided, no matter if this is done by a public field, a public property or public getter/setter functions.
Internal data IS NOR HIDDEN NEITHER ABSTRACTED just by routing access to it through a property!
To answer your question:
- Avoid public properties if you are writing an object
- Use public propertiers if you are writing data structures (a public field would do the job, too)
使用私有字段生成公共访问器会在用户代码和您的类之间建立契约。理想情况下,该合同不应因代码修订而改变。
在 C# 中,强制遵守契约的方法是使用
接口
。接口将允许您指定所需的方法和属性实现,但不允许指定字段。此外,在 .NET 的各个方面,属性通常比字段更受青睐。例如 PropertyGrid 控件仅枚举属性,ASP .NET MVC 模型类需要属性等。
Generating public accessors with private fields establishes a contract between user code and your class. Ideally, this contract should not change over revisions to code.
In C#, the way to enforce contract compliance is with an
interface
. Interfaces will allow you to specify required method and property implementations, but does not allow for fields.Moreover, in various points of .NET, properties are often preferred over fields. e.g. PropertyGrid control only enumerates properties, ASP.NET MVC model classes require properties, etc.
与本线程中的其他帖子一样,我将指出 C# 中的属性只是您提到的访问器函数的特殊情况。事实上,您可以在对象的 IL 中对 get_Property 和 set_Property 方法进行微调,这些方法具有指示它们是属性的标志,对于实现 add_ 和 remove_ 前缀方法的事件也是如此。
处理抽象时的一个重要区别是设置属性是否会作用于对象,而不仅仅是更新内部状态或抛出 PropertyChanged 异常。
如果您查看大量内部 BCL 对象,就会发现属性的实现方式使得您可以按任意顺序设置所有属性来配置对象。如果进行任何复杂的处理,那么通常描述将要发生的情况的方法是更好的选择。
Like other posts in this thread I'll point out that properties in C# are just special cases of accessor functions that you mention. In fact you can fine the get_Property and set_Property methods in the IL on your object that have a flag that indicates they are properties, the same is true for events which implement add_ and remove_ prefixed methods.
One important distinction when dealing with abstractions is whether setting the property is going to act on the object other than just updating the internal state or throwing a PropertyChanged exception.
If you look at a lot of the internal BCL objects, the properties are implemented in such a way that you can set all the properties in any order to configure the object. If any complex processing is done, then usually a method that describes what is going to happen is a better choice.
实际上,通过使用属性,例如
您正在隐藏其数据,因为有一个隐式变量来存储 SomeValue 属性设置和返回的值。
如果你有
那么你就会明白我的意思。您隐藏了对象的数据
someValue
并使用 SomeValue 属性限制对其的访问。Actually by using a Property e.g.
You are hiding its data as there is an implicit variable to store the value set and returned by the SomeValue property.
If you have
Then you'll see what I mean. You're hiding the object's data
someValue
and restricting access to it using the SomeValue proiperty.