问题
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!
回答1:
Public properties are fine. Not having to write explicit GetHeight()
and SetHeight()
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
public int Height { get; set; }
into
public int Height { get { return m_width; } set { m_width = value; } }
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.
回答2:
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.
回答3:
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:
class foo
{
public:
int x;
};
The corresponding term in C# would be a public field:
class foo
{
public int x;
}
What we name in C# as properties would be setters and getters in other languages:
C#:
class foo
{
public int X { get; set; }
}
corresponding C++:
class foo
{
private:
int x;
public:
void setX(int newX) { this->x = newX; }
int getX() { return this->x; }
}
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.
回答4:
When you are finished Clean Code I would recommend you read Bob Martin's other book:
Agile Principles Patterns and Practices In C#
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:
public class OrderData
{
public string customerId;
public int orderId;
public OrderData() {}
...
}
The following validation of the use of Public data deals with your question:
Don't be offended by the use of public data members. This is not an object in the true sense. It is simply a container for data. It has no interesting behavior that needs to be encapsulated. Making the data variables private, and providing getters and setters would be a waste of time. I could have used a struct instead of a class, but I want the OrderData to be passed by reference rather than by value.
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.
回答5:
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.
回答6:
Properties are in fact methods.
The compiler compiles properties to get/set MIL methods.
回答7:
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.
回答8:
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.
回答9:
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)
回答10:
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.
回答11:
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):
public void setHeight(int newHeight)
{
if (newHeight < 0)
height = 0;
else if (newHeight > 200)
height = 200;
else
height = newHeight
}
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.
回答12:
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.
回答13:
Actually by using a Property e.g.
public class Temp
{
public int SomeValue{get;set;}
public void SomeMethod()
{
... some work
}
}
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
public class Temp
{
private int someValue;
public int SomeValue
{
get{ return this.someValue;}
set{ this.someValue = value;}
}
public void SomeMethod()
{
this.someValue++;
}
}
Then you'll see what I mean. You're hiding the object's data someValue
and restricting access to it using the SomeValue proiperty.
来源:https://stackoverflow.com/questions/3195075/clean-code-should-objects-have-public-properties