81. Access Modifiers
Classes are used to embody an abstraction of some real or virtual entity. You can probably guess what a BankAccount or an EmailMessage class embodies. In some cases we might be happy for other code to change a value held in a class instance or to run a method. However, in the case of a BankAccount class we are likely to need some sort of information hiding that moderates what other code is allowed to do:
- The
balancefield shouldn’t be directly accessible. Rather, two methodsdepositandwithdrawalhave to be used. - The
withdrawalmethod should not allow you take take out more money than the current balance.
In Groovy we can implement the business logic just described through the use of Access Modifiers.
Access modifiers are keywords (public, private, protected) that determine if another class can use an element (such as a property, field or method) of the class being described.
-
publicelements can be accessed by all other classes and code -
privateelements are only accessible from within the class itself -
protectedelements are only accessible from subclasses and within their own package
Two things to keep in mind:
- Groovy applies
publicby default so you don’t need to explicitly declare anything aspublic. - Providing an access modifier means that
defisn’t needed when you’re using dynamic types:-
private balance = 0is preferred overprivate def balance = 0 - Similarly for methods:
private applyAccountCharges() {...}rather thanprivate def applyAccountCharges() {...}
-
For our BankAccount class we can make the balance field private:
class BankAccount {
private Integer balance = 0
Integer withdrawal(amount) {
if (amount > balance) {
throw new Exception('Insufficient balance')
}
balance -= amount
}
Integer deposit(amount) {
balance += amount
}
}
def acct = new BankAccount()
acct.deposit(100)
acct.withdrawal(150)
In the example above I set the balance field to private and then provide two public methods to allow for other code to perform a deposit or a withdrawal. The latter method even throws an exception if you try to take out too much.
Now here’s “the rub”. Groovy doesn’t actually enforce the access modifier. That means that, given my BankAccount class I could still write acct.balance = 1_000_000 and access the field directly. A Python programmer might shrug at this and state that it’s a matter of respecting the original programmer’s intention. A Java programmer might be shocked that Groovy doesn’t throw an exception or an error.
I’m usually pretty happy with the Python approach but if it was really a concern I could add the following method to my BankAccount class, as seen in the next example:
class BankAccount {
private Integer balance = 0
Integer withdrawal(amount) {
if (amount > balance) {
throw new Exception('Insufficient balance')
}
balance -= amount
}
Integer deposit(amount) {
balance += amount
}
private setBalance(amount) {
}
}
def acct = new BankAccount(balance: 200)
assert acct.balance == 0
def acct2 = new BankAccount()
acct.balance = 100
assert acct2.balance == 0
Groovy generates setters and getters for properties but I need provide them for fields. In the case of the balance field, the setter method named setBalance is actually called when I do something like acct.balance = 1_000_000. Knowing this, I overrode the setter Groovy would have created with my own version that does nothing and I also used the private modifier. This does two things:
- The
privatemodifier reinforces to other developers that they should not try to directly change the value ofbalance - If the other developers just don’t listen then I ignore their attempt to change the
balance.
Whilst my empty setBalance method helps prove a point, having to do that too often will reduce readability and annoy me with having to write lots of vacant code to protect my code from others who don’t listen. Essentially I take the approach that developers are (usually) sensible people that understand what they’re being asked not to fiddle with. If they fiddle then they can expect a weird outcome. So feel free to write a method with the signature private doSomethingEvil(), add some code that deletes all files and see who doesn’t pay attention :-)
Applying Access Modifiers
The following access modifiers are available:
- Classes:
publicprotected
- Fields
publicprivateprotected
- Methods
publicprivateprotected
Remember, you don’t need to explicitly declare an element as public as this is the default.
- If you want to really get into this topic, start with http://docs.oracle.com/javase/tutorial/essential/environment/security.html↩