When does it make sense to use a public field?
This is a question I have had for a while now:
When does it make sense to 开发者_JS百科expose a field publicly like so?
public class SomeClass()
{
public int backing;
}
The downside of doing this (in addition to angering OOP elitists) is that you have to introduce a breaking change to your API if you ever need to add any logic on top of this data. I suppose that is what the elitists are on about.
Best practice in Java and C# has long been to use getters/setters or properties to access fields.
public class SomeClass()
{
private int backing;
public int getBacking()
{
return backing;
}
public void setBacking(int v)
{
backing = v;
}
}
C# has evolved this to pretty simple syntax with automatic properties:
public class SomeClass()
{
public int Backing { get; set; }
}
Lazy me still feels this is too long though since it something I find myself doing a lot. More importantly, I am not sure I know where a public field would make more sense.
Why not just treat publicly declared fields as properties (or methods) behind the scenes? That way it would be impossible to anger decoupling gods and be a bit less typing to boot.
public class SomeClass()
{
public int backing; // The same as public int backing { get; set; }
}
For a property that does nothing but wrap the underlying field, I am pretty sure the JIT optimizes the method calls away so performance is probably not the issue. Any thoughts? (other than the proper case convention for the field name)
EDIT: Thanks for all the responses. I feel like perhaps not everyone is understanding my question though. When would a public field be a better choice than a property? Why is it a better choice? If the only reason is convenience (less typing and clutter), then what would be the downside of having the compiler generate a property "under-the-hood" whenever a public field is encountered. Basically, it would be impossible to create a true public field (because they would all be properties). What would be wrong with that? Thanks.
In my opinion, when you design a structure of a class you should pay more attention to future changes and should always be friendly to them. If a future requirement need you to do some logic before returning a value instead of just returnning the value of the field, you'll have to change the interface of the class, and all users of your library will have to change. That usually become a disaster.
Keep in mind, the open / close principle.
When does it make sense to expose a field publicly?
Among other places, on private classes as below.
public class MyOuterClass
{
private class MyInnerClass
{
public int val ; // why bother w/boiler plate
}
}
Here is the summary of pros and cons of public fields:
Advantages
- Less clutter in the code
- Better performance (in some cases)
Disadvantages
- Representation can't be changed without changing the API
- Invariants can't be enforced (unless the field is immutable)
- No additional actions can be taken when accessing these fields
So when should we use public fields? Depends. It is obvious that for public classes disadvantages outweigh the advantages. Possible problems with evolving the code inside the package are far worse than more clutter in the code and minor performance impact.
However, a class can be package private or even private nested, in which case the probable changes to the code will be localized. Therefore it is absolutely possible to use public fields. Also there are cases when performance difference is not so little. For instance, Android Developers guide claims that it is a good practice to use direct field access instead of getters/setters where it is possible because it is several times faster.
To sum up, I will quote one of my favourite books, Effective Java by J. Bloch, Item 14:
In summary, public classes should never expose mutable fields. It is less harmful, though still questionable, for public classes to expose immutable fields. It is, however, sometimes desirable for package-private or private nested classes to expose fields, whether mutable or immutable.
One of the scenarios when public field is a better choice is providing constants of your class.
For example, see:
public const double PI
defined in System.Math.
This approach is favored because it explicitly informs consumers of your class, that this member does not include any logic, validation or any other state-related operation, thus can be used in whatever context you want.
The other one I can think of, is when you need classes as containers for simple operations (or just for passing the large number of params to a method), as an example see System.Windows.Point
. In most cases, these containers are modeled as structs though.
I think it makes sense when you want to group some variables/objects (kind of like a C struct
). For example:
class Pixel {
public int x;
public int y;
Color c;
// Other Pixel related information
}
As there are no methods, nothing breaks if a wrong value is used and it nicely puts these variables together.
So the best answer I can give is that when you do magic via reflection, as one is wont to do when taking advantage of a statically typed language, properties have meaning over fields. From things like ORM tools, to mappers, and to binding data, properties can have different meaning than fields from that behavioral standpoint.
The JITter doesn't turn properties into fields, it can inline them, though I won't promise it does in all cases.
On projects with non-trivial complexity it is rarely - but sometimes - a good idea to use public fields. One example that comes to mind:
/**
* A two-dimensional mathematical vector. Immutable so instances may be freely shared
* without violating encapsulation.
*/
public class Vec2 {
public final int x, y;
// bunch of constructors and methods omitted
}
Rationale: It is exceedingly unlikely that the internal representation will need to be changed, or any kind of operation be performed when reading x
or y
. That is, using a setter confers no benefit here.
However it would confer some costs:
- The public final field will make it abundantly clear the class is immutable, with a getter, you have to trust the documentation comment. (Do note that the absence of a setter does not imply immutability, because some other method might assign the field)
- Code accessing the vector would be slightly less readable, as get() confers no meaningful semantic information, but still has to be skipped over when reading the code (at least in Java, C# is better here).
- This being an extremely low level class frequent use is possible, and invocation overhead might become an issue. Yes, the virtual machine can perform inlining in many cases, but at least for non-final methods, some overhead is likely to remain even if no subclasses are currently loaded.
One scenario, at least in .NET, is interop with C APIs. You'll often declare C# or VB versions of Windows API structs, and it's common to use public fields for these because the normal reason for making fields private -- to prevent someone messing with them behind your back -- breaks down. In this case, you know that something is going to be changing the fields behind your back -- that's the whole purpose of having the struct!
Of course you typically won't expose those unencapsulated structs to application code -- you'll treat them as private elements of the P/Invoke module, so application code still won't be dealing with the public fields.
Best practice in Java and C# has long been to use getters/setters or properties to access fields.
I think that is the first problem: the idea that if you have a getter you must also have a setter. This is a mistake; in many cases a setter is unecessary because there is no real need to modify the attribute value of an object, and removing the possibility simplifies the class.
The extreme cases is to have no mutators at all. The final stage to making the class immutable is never to make mutable field values (remember, Java final
is not like C++ const
) directly accessible. And small value classes should be immutable. Only a getter method can provide safe access to potentially mutable fields, by creating a copy (in C++ you simply have a getter that returns by value). You could dispense with the getter for those fields that do not require defensive copying, but then some fields in a class might require a getter and some not. But that would be confusing,
You can use, in java, a public field, and then add some logic to it, like if there was a getter, using AspectJ, there including avoid writing to it if not from a specific psckage etc...
While this is a major improvement, that speeds up coding and still leaves a lot of space for future improvements without having everyone to rewrite all their code, it is not used that much, cause elitists are notoriously bigots.
Back to your question, since jit there is not great improvement in using public fields as opposed to getters/setters, and since IDEs have automatic getters and setters generation there is no real programmer overhead in using getters and setters. In years of Java programming I've used public fields only a couple of times, and always ended up converting them to getters/setters pairs.
Among all the other answers, there are some situations where you have to use public fields in public classes. Using Unity 3D for instance. The serializer only serializes the fields and not the properties (for better performance). So before implementing your class, research on how the libraries and the frameworks you're using work. They might need some of your fields to be public in order to work as expected.
精彩评论