I had some training Dec 2016 on Object Oriented Programming.
It was pretty mind blowing. There was a lot of frustrations during the training. Took me a few days to switch my mind around to the approach the class was emphasizing. Which is very much Object Oriented Programming. Not just coding in an object oriented language; but really structuring and designing in an Object Oriented fashion.
There were a few major changes in how I view code and code smells from this training.
Big change one: Getter/Setters are code smells.
Big change two: If
's are code smells.
I'll cover the second one in another post. It'll be a whole slew of pattern posts.
This is about not having getters/setters in objects.
I'm finding I still lack requisite experience to know how to get rid of all my getter/setters. There's gotta be a way, but my books are failing me!!!
For now though, I strive to find ways, and will work on doing it where I know I can.
For this post; we'll be looking at classes and how to not use getters/setters. This is done via truer encapsulation. Using a getter still exposes the internal data of an object. The getters do hide if the specific implementation changes, but most of the time when the type changes the code gets updated and the getters return the new type... defeating the purpose of encapsulating the data.
This is an early post in my blogging efforts; and covering what I consider an important topic - I expect to be revisiting it in the future of my blogging practices. Either for new information or "oh wow - my writing sucked" points of view.
Do not use getters. Don't expose the raw data. Done?
The example for I'll use for this is a Employee class. My normal approach for this would have been to create a DTO with (in java) public final fields.
This was nice and clean from the perspective of immutability. No data could be changed. This made it nice to not have the boilerplate get/set methods for each piece of data.
This didn't feel good, but better than a slew of getter/setters; or even just getters.
A usecase that exemplifies the idea behind this something like if(employee.role == "Manager")
. We're getting the employee
's role to do something with it. In this case we're asking "Are you a manager?". We can hide the role
data member by creating isTYPE
methods for each available role.
This changes the class to look like
The use changes to if(employee.isManager())
.
If we're displaying the users's name, which get's a little tricker - mostly 'cause I was wrong about this originally.
The Employee
class has a firstName
and lastName
field. If there's a need to display the full name; it's be something where two fields are retrieved, combined. There's some manipulation of the data outside of the class - Sounds like a violation of encapsulation of the data.
To include the full name; the best approach is to pass in the object that will receive the full name. This can be a StringBuilder
type object; or a String
to String.format
into; Or if at the UI level, I've been including a method on the class (employee in this case). This will (coming from Android) look like employee.writeFirstName(textViewControl)
. This has an unfortunate side effect of the employee object knowing about a ui control. Which is a trade off between exposing some data.
If there's no other recourse; which I think knowing about the UI control is a recourse; then returning a copy of some data is the last resort.
public String fullName(){
return String(firstName + " " + lastName);
}
But don't do that. It's really the second least desirable option. The another is returning the raw data.
Stream, Scan, Build
One thing I've tried to do; and it doesn't feel right; is use a Stream
or a Scanner
as a return type on a method. The other I tried (and it's described in the VBM post) is to pass in a StringBuilder
. It ... gets it the job done. I really don't like these things. If there's no acceptable way to pass in the object to get the result; which is why I tried StringBuilder
; then Stream
/Scanner
as a return type is true hiding of the underlying data type.
Program to an Interface
One thing I've been able to do recently; and there's no guarantee it'll work in all cases or languages; on Android is to create an interface that matches the signature of a method in the UI widget. Then we can pass in the widget as an interface;
public void fullName(SetText item){
item.setText(firstName + " " + lastName);
}
A large part of this will be what you're trying to do; but if it's doing SOMETHING; then the object is probably better suited to doing it.
These are some early thoughts on a hefty subject. I'll be doing another which will hopefully be a bit more robust.