Sometimesit is desirable to allow access to a property that returns a dynamically computed value, or you may want to reflect the status of an internal variable without requiring the use of explicit method calls. In JavaScript, this can be accomplished with the use of a getter.
An object property is either a data property or an accessor property, but it cannot simultaneously be both. Read Object.defineProperty() for more information. The getter syntax allows you to specify the getter function in an object initializer.
Getter properties are defined on the prototype property of the class and are thus shared by all instances of the class. Unlike getter properties in object literals, getter properties in classes are not enumerable.
Getters give you a way to define a property of an object, but they do not calculate the property's value until it is accessed. A getter defers the cost of calculating the value until the value is needed. If it is never needed, you never pay the cost.
An additional optimization technique to lazify or delay the calculation of a property value and cache it for later access are smart (or memoized) getters. The value is calculated the first time the getter is called and is then cached so subsequent accesses return the cached value without recalculating it. This is useful in the following situations:
In the following example, the object has a getter as its own property. On getting the property, the property is removed from the object and re-added, but implicitly as a data property this time. Finally, the value gets returned.
\n Getters give you a way to define a property of an object, but they do not\n calculate the property's value until it is accessed. A getter defers the cost\n of calculating the value until the value is needed. If it is never needed, you never pay\n the cost.\n
\n An additional optimization technique to lazify or delay the calculation of a property\n value and cache it for later access are smart (or memoized) getters.\n The value is calculated the first time the getter is called and is then cached so\n subsequent accesses return the cached value without recalculating it. This is useful in\n the following situations:\n
\n Note: This means that you shouldn't write a lazy getter for a property whose value you\n expect to change, because if the getter is lazy, then it will not recalculate the\n value.\n
\n In the following example, the object has a getter as its own property. On getting the\n property, the property is removed from the object and re-added, but implicitly as a data\n property this time. Finally, the value gets returned.\n
You can tell them by the twitch in the left hand side of themouth when they see a getter method, there's swift pull on theirbattleaxe and a satisfied cry as another getter is hewn unmercifullyfrom a class which immediately swoons in an ecstasy of gratefulnessat the manly Getter Eradicator's feet.
Alright, maybe my return to English beer is affecting me a bittoo much, but Chris's gentletweak struck a pet peevlet of mine. I've often come across peoplewho tell you to avoid having getting methods on classes, treatingsuch things as a violation of encapsulation, Allen Holub's article isone of the best known.
The general justification is that getters violateencapsulation. If I've got a bowler class with fields forovers, runs and wickets, then adding getters (getOvers, getRuns,getWickets) is little better than just making the fields public.
There's some sense to this argument, and I certainly suggest thatyou shouldn't write accessors until you really need them, but it alsobrings in the danger of missing the point of encapsulation. For me,the point of encapsulation isn't really about hiding the data, but inhiding design decisions, particularly in areas where those decisionsmay have to change. The internal data representation is one example ofthis, but not the only one and not always the best one. The protocolused to communicate with an external data store is a good example ofencapsulation - one that's more about the messages to that store thanit is about any data representation. When you are thinking aboutencapsulation I think it's better to ask yourself "what piece ofvariability are you hiding and why" rather than "am I exposing data".(Craig Larman wrote a nicecolumn for me on this.)
Although the defense of encapsulation is the common rallying cryfor getter eradicators, I think the real motivation for them is rathermore reasonable and pragmatic. There's a hell of a lot of code outthere in OO languages that is procedural in design. The OO communitymay have 'won' in the sense that modern languages are dominated byobjects, but they are still yet to win in that OO programming is stillnot widely used. As a result it's still common to see procedures thatpull data out of an object to do something, when that behavior wouldbetter fit in the object itself - a violation of the pragmaticprogrammers principle of "TellDon't Ask". You can only do this kind of procedural programming ifyou have getters, so telling people to get rid of getters helps pushthem to move behavior into the right place.
I have a lot of sympathy with this motivation, but I fear thatjust telling people to avoid getters is a rather blunt tool. Thereare too many times when objects do need to collaborate by exchangingdata, which leads to genuine needs for getters.
If we're looking for a simple rule of thumb, the one I prefer isone that I first heard from Kent Beck, which is to always beware ofcases where some code invokes more than one method on the same object. Thisoccurs with accessors and more reasonable commands. If you ask anobject for two bits of data, can you replace this with a singlerequest for the bit of data you're calculating? If you tell anobject to do two things, can you replace them with a single command?Of course there are plenty of cases where you can't, but it's alwaysworth asking yourself the question.
Another good warning sign of trouble is the Data Class - a classthat has only fields and accessors. That's almost always a sign oftrouble because it's devoid of behavior. If you see one of those youshould always be suspicious. Look for who uses the data and try tosee if some of this behavior can be moved into the object. In thesecases it can be useful to ask yourself 'can I get rid of thisgetter?' Even if you can't, asking the question may lead to somegood movements of behavior.
Allocation of behavior between objects is the essence ofobject-oriented design, so like any design, there isn't a hard andfast rule - rather a judging of trade-offs. Putting the behaviorin the same class as the data, what Craig Larman calls "InformationExpert", is the first choice to consider. But it isn't the onlyroute. Layering often trumps this, many of the Gang of Four patternsseparate data from behavior for particular needs. A good rule ofthumb is that things that change together should be together. Dataand the behavior that uses it often change together, but oftenyou see other groupings that matter more.
Okay, just about everywhere I read, I read that getters/setters are "evil". Now, as a programmer who uses getters/setters often in PHP / C#, I do not see how they are alive. I have read that they break encapsulation, etc etc, however, here is a simple example.
So, how else would I impose this restriction without using getters/setters?How else would I modify a property without using getters/setters?Should armorValue just be a public member variable in case 1, and the getters/setters used in case 2?
One pitfall of C++ is to create non-const reference getter, which allows also modification. That's same as returning a pointer to internal data, and will lock that part of internal implementation, and is really no better than making field public.
The evil here is not, IMO, so much from "breaking encapsulation", as from simply defining a variable to be of one type (e.g., int) when it's really not that type at all. Looking at your example, you're calling Armor an int, but it's really not. While it's undoubtedly an integer, it's certainly not an int, which (among other things) defines a range. While your type is an integer, it's never intended to support the same range as an int at all. If you want Armor to be of a type integer from 1 to 500, define a type to represent that directly, and define Armor as an instance of that type. In this case, since the invariant you want to enforce is defined as part of the type itself, you don't need to tack a setter onto it to try to enforce it.
Depending on the situation, you might prefer to define (for example) a saturating type where attempting to assign an out of range value is fine, but the value that actually is assigned will simply be the nearest value that is within range.
Bottom line: the (or at least "one") major problem with getters and setters is that they usually point to your having defined a variable as being of one type when you really want some other type that happened to be sort of similar in a few ways.
Now, it's true that some languages (e.g., Java) fail to provide the programmer with the tools necessary to write code like that. Here I'm trusting your use of the C++ tag to indicate that you really do want to write C++ though. C++ does provide you with the necessary tools, and (at least IMO) your code will be better off for your making good use of the tools it provides so your type enforces the required semantic constraints while still using clean, natural, readable syntax.
3a8082e126