Brainless getters and setters (those that serve only the purpose of exposing a private member variable) don't belong in your class files. Here's why.
Object Orientated Programming is about interfaces. You create an instance of an object because you need it to do something, whatever that something may be. How it does that something is determined by it's interface. The interface to an object is everything that is marked "public" inside of it class definition.
In Flash there are 3 elements that can be made public to compose the interface of an object - variables, properties, and methods. The key to everything I'm about to say comes from the basic principle that variables and properties have the exact same behavior from an interface standpoint. That is, properties look exactly like variables even though behind the scenes they are very different. See the livedocs for more information about properties. The beauty of OOP is that the "behind the scenes" stuff does not matter to users of a class.
What does this mean to you, the creator of a class? It means that you can have the exact same interface to your class regardless of whether you use public variables or public properties. A user of class knows they can set "name" to "Darron" because the interface to your class says they can. What happens behind the scenes is not important since the implementation is encapsulated by the interface. Encapsulation is one of the main principles of OOP, so let's use it to our advantage.
Consider this example. This is a typical Person class with a firstname and a lastname.
class Person {
// private backing variables for public properties
private var _firstname:String;
private var _lastname:String;
public function Person(firstname:String, lastname:String) {
this.firstname = firstname;
this.lastname = lastname;
}
public function sayHello():Void {
trace(this.firstname + " " + this.lastname + " says hello!");
}
// create a "firstname" property
public function get firstname():String {
return this._firstname;
}
public function set firstname(value:String):Void {
this._firstname = value;
}
// create a "lastname" property
public function get lastname():String {
return this._lastname;
}
public function set lastname(value:String):Void {
this._lastname = value;
}
}
// create myself as a person
var p = new Person("Darron", "Schall");
p.sayHello();
// like magic, turn me into Jesse Warden
p.firstname = "Jesse";
p.lastname = "Warden";
p.sayHello();
Is there anything wrong with the above example? Obviously there is since I'm using it as an example, but it's not so obvious by just looking at the class. I was always taught in college to make class variables private. There is a lot of merit to that statement - you don't want someone using your class to have access to the private internals of your class because they might be able to break it by setting "bad" values. To keep your class in a consistent (not broken) state you provide accessors and modifiers (getters and setters) to control access to the private data of the class.
So I did everything by the book and created public firstname and lastname getter/setter pairs that allow users of my Person class to modify internal data. The problem is... what I just did was completely unnecessary and added extra bloat and filesize to my Person class. Because those getter/setter pairs have "no brain" and just provide access to the private variables, I should not have made public properties at all. They don't add anything to the class file that couldn't have been gotten by simple making the private variables public, so they're useless.
Again, we're talking about interfaces here. This new Person has the exact same interface as the old person:
class Person2 {
public var firstname:String;
public var lastname:String;
public function Person2(firstname:String, lastname:String) {
this.firstname = firstname;
this.lastname = lastname;
}
public function sayHello():Void {
trace(this.firstname + " " + this.lastname + " says hello!");
}
}
// demonstrating the interface remained the same
// create myself as a person
var p = new Person2("Darron", "Schall"); // just changed Person to Person2
p.sayHello();
// like magic, turn me into Jesse Warden
p.firstname = "Jesse";
p.lastname = "Warden";
p.sayHello();
You can see the Person2 is a whole lot smaller and I would argue more maintainable because there's less code in the class file to wade through. Because it has the exact same interface, Person and Person2 can be used interchangeably. There's nothing wrong with making a variable public if you have a "no-brain" getter/setter pair that exposes it anyway.
In fact, here are some reasons to use public variables over "no-brain" properties:
- You remove the overhead of having to call a method everything you access the property, since you can access the variable directly
- There is no "set calls get" bug since we're not dealing with properties anymore.
- Easier to read, less typing, easier to code, less clutter in source code. All of these can be filed under easier to maintain.
- Smaller filesize - since your class files are downloaded with the .swf, the less code in your class file means the less that users need to download.
Additionally, if you decide that you should later need to switch to using a property for a consistency check, it's very easy to refactor Person2 to support this. Again, the interface remains exactly the same so everyone using your class does not have to change their code. Rather, "it just works" because the implementation is encapsulated.
An example of the refactoring... let's say you want to only set the firstname if the value it is being set to is not an empty string. With a public variable we can't check this, but with a property we can. Here's the refactored Person2 class, which I named Person3.
class Person3 {
private var _firstname:String;
public var lastname:String;
public function Person3(firstname:String, lastname:String) {
this.firstname = firstname;
this.lastname = lastname;
}
public function sayHello():Void {
trace(this.firstname + " " + this.lastname + " says hello!");
}
// provide access to private variable
public function get firstname():String {
return this._firstname;
}
// provide a consistency check in the setter
public function set firstname(value:String):Void {
if (value.length > 0) {
this._firstname = value;
}
}
}
There are only 3 changes that I made. First, I marked firstname as private and renamed it to _firstname since firstname will become the property name. Then I added a getter to access _firstname. Finally, I added a setter that checks to make sure firstname is not set to an empty string. That's all there is to it, nothing else in the class file needed to change. Refactoring public variables to public properties is really that simple.
Now, with all of that being said, there are still times that you want public properties over public variables. Here are a few of the common cases:
- The property is read-only (that is, only a getter is provided)
- The property doesn't directly relate to a "backing" private variable
- get date might return month + "/" + day + "/" + year
- You need to provide a consistency check for the setter (like I did in the above Person3 class)
There may be more, but those seem to be the most common ones.
So, all of that to say this: If you're using "no-brain" getter/setter pairs, considering refactoring to public variables instead. The interface to your class will stay the same, and you can remove some bloat from your class files in the process. As demonstrated, it's always easy to refactor at a later time if you need to.