Skip to content

Instantly share code, notes, and snippets.

@mobiRic
Last active June 15, 2018 17:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mobiRic/62eeb28d67508f5d319ff8b1d1a7fbb1 to your computer and use it in GitHub Desktop.
Save mobiRic/62eeb28d67508f5d319ff8b1d1a7fbb1 to your computer and use it in GitHub Desktop.
Some thoughts and sample code I have put together to try and explain concepts during the Google Africa ALC v2.0 Udacity course.
Here's the followup, which is called *composition*. This pattern is favoured in React Native and Flutter, and seems to be gaining popularity. Instead of extending from one class, we wrap one class in another. Some people say it is much better - I leave that up to the team to read up on.
Here I'm going to have an immutable `message` in some `HandWriting`. Anyone can look at the message by calling `HandWriting.readMe()` which is my fun example of a "getter" type method. We could rename it to `getMessage()` if you really want.
I also have a `Letter` that I'm writing to a friend.
It doesn't really make sense to `extend HandWriting` because a letter is a slightly different concept to the writing inside it.
But the `Letter` does contain some writing. Also has a friend's name that we are sending it to.
Of course, to say that you are reading the Letter, also means you are reading the HandWriting on the letter, right? So the "getter" on the Letter should call into the getter on the HandWriting.
This would not be possible if we just had some `public String message` variables - we need to have actual methods (getters) in cases like this to add the extra flexibility.
```/**
* This class represents a message that someone has written on a piece of paper.
* <p>
* It could be extended later to include other properties, like what
* colour pen it was written in, or the language.
*/
public class HandWriting {
/**
* Every piece of handwriting contains a message which cannot be changed.
*/
private final String message;
public HandWriting(String message) {
this.message = message;
}
/**
* Anyone can read the handwriting.
*
* @return the message that was written
*/
public String readMe() {
return message;
}
}```
```/**
* A letter is a message addressed to a friend.
* <p>
* It is more than an extension of HandWriting, but it does contain some writing.
*/
public class Letter {
/**
* A Letter is addressed to someone.
*/
private final String friendsName;
/**
* A Letter contains a handwritten story.
*/
private final HandWriting storyForMyFriend;
/**
* Write a letter to someone.
*
* @param friendsName the friend you are sending it to
* @param storyForMyFriend a message that you want to send
*/
public Letter(String friendsName, String storyForMyFriend) {
this.friendsName = friendsName;
this.storyForMyFriend = new HandWriting(storyForMyFriend);
}
/**
* When you read the letter, you also need to read the HandWriting.
*
* @return the full letter including your friend's name
*/
public String readMe() {
return "Dear " + friendsName
+ "\n\n"
+ storyForMyFriend.readMe();
}
}```
So before I get to the code you asked for - there's a difference called "Inheritance vs Composition" which is 2 different ways of doing object orientation. Inheritance is the main one, and some languages favour composition.
I think we all know what inheritance is by now. So I've made a couple of fun classes which are very basic inheritance. I must trust that this makes sense.
This example is *inheritance*.
I've got a `Dog` and a `Pet extends Dog`. A Pet is more than a Dog because it has a name, for fun.
`Dog.wagTail()` is kind of a setter in the way that it changes the string variable.
`Pet.wagTail()` does some logging (like in the previous example) before calling up into super.
```public class Dog {
public static final String TAIL_WAGGING = "wag";
public static final String TAIL_NOT_WAGGING = null;
private String tail = TAIL_NOT_WAGGING;
public void wagTail() {
tail = TAIL_WAGGING;
}
}```
```public class Pet extends Dog {
private final String name;
public Pet(String name) {
this.name = name;
}
@Override
public void wagTail() {
Log.d("DOGS", name + " is happy");
super.wagTail();
}
}```
One person posts about immutable data. Can only do that properly with a getter and no setter. It is part of a bigger problem that I'll try explain, loosely, using people instead of classes...
Immutable is if you set something and don't let anyone change it again. So a public getter. And a private, or missing setter.
What about if you set something and you let your family & friends change it, but strangers can only read the value? Now we still talking about public getter, but maybe a protected setter, or default visibility. Classes that inherit, or are in the same package, can change it, but not others...
----------------------------
Another person posted a good article that I wanted to mention - using setters or getters allows us to run other code when the value changes. The article talks about using this for validation. We can also use it for logging the new and old values which can be very useful for debugging.
------------------------------
Then talking about OO design - sometimes we want to make a "wrapper" class. One that contains another class, and we want to pass values from the outside of our class into this wrapped class.
We don't want the users to have to know how the class works, so we don't let that wrapped object be public. So the user can't change the values on this object at all. Now we need to put getter & setter methods in our wrapper class, that call into the private object.
----------------
Lastly just a quick one that it makes it easier to see where code is reading or writing the value. In Android Studio you can ask who accesses a variable or field, but that gives you the reads & writes together (CTRL-b). But if you have getter, you can just see who reads the value by going to that method and CTRL-ALT-h.
Here's some sample code. I've copied the validation idea from one of the articles posted. I've also included useful code for logging a value from inside the setter. I'm sure you can see how a setter method can be much more useful than just using the public field...
``` /**
* A positive or zero number. The setter prevents this from becoming negative.
*
* @see #setNonNegativeNumber(int)
*/
private int notNegativeNumber = 0;
/**
* Sets the value of {@link #notNegativeNumber} if the parameter is >= 0.
* <p>
* If the supplied new value is less than zero this method throws an {@link IllegalArgumentException}.
*
* @param number New number to set. This must be zero or positive.
*/
public void setNonNegativeNumber(int number) {
// useful to log information in a setter sometimes
Log.d("VALIDATION", "Trying to set a new number: " + number);
// validation code like @Zakdroid's link
if (number < 0) {
Log.d("VALIDATION", "ERROR: number is less than zero!");
throw new IllegalArgumentException("Non-negative number required. Received: " + number);
}
// now we do the actual setting of the field
Log.d("VALIDATION", "Valid number received - setting field: " + number);
notNegativeNumber = number;
}```
@mobiRic
Copy link
Author

mobiRic commented Jun 15, 2018

Code is written in Slack markdown as it comes from conversations I've had with some of the learners on the Slack community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment