OOP Thought Process
This is it!
The entire philosophy underpinning object-oriented programming (OOP) is founded in the ideas of the next few lessons – starting here!
Don’t rush these concepts! They are essential!
Software development is more than coding!
What is the most difficult part about being an architect?
Is it creativity of the design, or knowing how to use drawing apps?
What is the most difficult part about being an artist?
Is it in expressing creativity, or knowing how to use a paint brush?
What is the most difficult part about being a landscaper?
Is it in designing a nice garden, or using a spade?
What is the most difficult part about being a software developer?
Is it in designing the program, or in coding it?
While it will involve some technicalities surrounding the coding, developing complex software is more about modeling a problem, designing a solution, and building it as a quality software solution to address that problem.
Software Quality… the “*ilities”
- Developing large and complex software systems is an Engineering discipline that requires meeting functional and non-functional requirements to a given problem.
- When you develop and deliver a software product, your attitude should not only be “great, it works”. You also need to consider:
- Maintainability: the code is easily extended with new features, implying it is understandable, documented, concise, self-descriptive.
- Modifiability: changing bits of the code is minimised to that region.
- Reusability: the code is written once, but can be used again. No evidence of “copy-paste-edit”, which welcomes more errors.
- Usability: the application is human-friendly and efficient to use, users intuitively learn and use it, and give meaningful error messages.
- Scalability: as the demand for the application increases, it should handle the increased stress and number of users.
- Reliability: the application is consistently accurate, without failure.
- Portability: the application executes on a range of platforms, operating systems, browsers with minimal re-coding.
- Testability, security, efficiency, accessibility, etc, etc…
Introductory OOP thinking…
You have already seen different types of data. For example, int
, boolean
, String
, and so on.
Let’s think of the String
type.
Conceptually, how would you characterise a String
?
This one is straightforward. We can say that:
- A
String
is a series of zero or more characters (letters, numbers, punctuation marks, etc), - The
String
starts with a"
, and - It ends with a
"
.
Conceptually, that’s it. There’s really nothing more to the String
.
At this stage, we don’t care how it is technically implemented. We just care about the concept or the idea of what a String
is. Simple.
So now imagine that you have a String
in front of you.
It doesn’t matter how many characters it has between the "
s, and it doesn’t matter what those characters are (if there are any). We just care that “it’s a String
”.
Now, think of the sorts of things you might want to do with an arbitrary String
.
What might you care about it? What are some things we might like to ask the String
, or what are some things we might ask it to do?
Some ideas:
- How many characters do you have?
- Do you have zero characters?
- What would you look like—as a
String
—if I were to copy-paste you n times? - What would you look like—as a
String
—if you got rid of all your “white space” characters at the start and end? - What would you look like—as a
String
—if you were to make all your letters upper case?
Notice how above we appear to be “speaking to the String
” as if it were able to respond to us. This language is intentional. We are trying to think of the String
as a thing that we can interact with.
Hopefully you are beginning to appreciate the versatility of thinking conceptually about a String
.
We’re not talking about any particular String
value, like "hello"
, " Welcome, please come in... "
, ""
, " "
, etc.
We’re only thinking at a conceptual level. We’re trying to define the blueprint of the String
class.
The above questions are all applicable to any given String
that might be in front of us.
And at this stage, we are only thinking abstractly.
Now it’s your turn…
Let’s use our imagination!
1. What’s the blueprint of the Pen
“type of data”?
Let’s get thinking!
Just above, we talked about the String
type.
Now, imagine the idea of the Pen
type.
We want to design the blueprint for the Pen
type:
Conceptually, how would you characterise a Pen
? You should be thinking in general about all pens. Don’t describe a specific/particular pen. Think about what properties/characteristics all pens have in common. Later on, you would be able to describe a particular pen by specifying actual values for those characteristics.
Hint: You can’t say “they all write”—that’s not a characteristic. You can’t give a value to “they all write” in order to describe a particular pen.
Now, imagine that you have a particular Pen
in front of you. You can’t actually see what this pen looks like, and you don’t know anything about it. All that you know is, you have a Pen
in front of you. In fact, this particular pen is behind a curtain. We can even give this mysterious pen some reference, so we know what to refer to it as—regardless of what is actually behind the curtain!
Now, think of the sorts of things you might want to do with this arbitrary Pen
. What might you care about it? What are some things we might like to ask the Pen
, or what are some things we might do to it?
Hint: You don’t have to only think of things you can literally do to the pen. You can also think more abstractly, such as operating on the “characteristic(s)” of that pen. For example, we might want to empty out all the ink inside it. We might want to ask what material is it made from. We might want to open the pen (click or remove its cap). We might want to close the pen (click or place its cap back on).
2. The Snake game
Imagine we want to recreate the classical Snake game:
Think about what we would need to model and represent:
- What are the entities (“things”) in our model?
- What properties/characteristics do those entities have?
- What actions can those entities do, or can we perform on them?
- What are the relationships between those entities?
What are the different levels of required details?
- A big part of OOP modeling is about simplifying problems, and hiding unnecessary details.
- e.g. does the food need to know what speed the snake is moving at?
The blueprint OOP analogy
The blueprint is a helpful analogy to understand classes and instances.
We will review this analogy later on, to cater for more OOP concepts as we introduce them.
- A blueprint defines the structure and functionality of something (e.g. a house).
- Different objects have different blueprints.
- A blueprint itself is nothing more than a formalised plan/design!
- But it allows you to make instances of what the blueprint represents.
- For example, an architect designs a blueprint for a particular house design (3 bedrooms, 2 bathrooms, etc).
- That blueprint can then be used to create many instances of that exact same house design, with each house instance potentially having a slightly different wall colour, carpet, etc.
- If you were to drive past those houses, from the outside you will notice they all look the same and will even comment “haha, looks like they came from the same blueprint”. That’s because they belong to the same class.
Appreciate that OOP involves an element of design to represent some object in the problem space that we wish to model.
This allows us to formally “draw up” the blueprint.
Going back to our pens example above: from the blueprint of what a Pen
class constitutes, we can create any number of instances.
From ideas, to classes, to instances
So, how do we make an instance of a Pen
?
Easy. We hold the blueprint and say “Abracadabra, new
Pen!”
This creates an instance of that blueprint.
We can create multiple instances from the same blueprint.
An instance is only created when you use the magic word: new
.
Making more than just pens
Clearly we can do more than create pens. The idea is that we define a blueprint for whatever concept we need to model.
We can then create as many instances of that blueprint as we want.
Each instance can have its own values for the properties that the blueprint defines.
- “Abracadabra,
new Car("red", 29000)
!”- Create a new car instance, and
- Set its colour as red with a price tag of $29,000.
- “Abracadabra,
new Car("blue", 34990)
!” (another car)- Create yet another car instance, and
- Set its color as blue, with a price tag of $34,990.
- “Abracadabra,
new Person("Jenny", 18, 165)
!”- Create a new person instance, and
- Set this person’s name as “Jenny”, with age 18, and height of 165cm.
Videos to watch
The pillars of OOP
This is an overview of the main pillars of OOP.
We will cover them all in the first half of the course.
For now, only watch the following parts of this video:
- Abstraction (the first 3 minutes).
- Encapsulation (the last 3.5 minutes from 7:56).
You can safely ignore and skip the following parts for now:
- Inheritance
- Polymorphism
Classes and objects
This is essential. Watch it 17 million times.
- For this lesson, don’t get too caught up with the code.
- We will break this down further in the next few lessons.
- For now, just begin to appreciate the idea of “classes” versus “instances”.
For the purposes of this course, we will humbly rewrite the code as follows:
Get your hands dirty!
This exercise builds on the example in the above video.
It has the following differences:
- We use a more meaningful variable name (
pika
instead ofp1
). - It uses
private
andpublic
explicitly.- It’s important to be explicit on the level of encapsulation we want.
- It explicitly initialises
this.name
in the zero-parameter constructor.- It’s important to always explicitly initialise all variables/fields.
- We’ve added a
printDetails()
method, just so we can see a little better what’s happening.
Here’s how we can visualise the Pokemon
class, as a blueprint:
Edit the code below:
- Modify the
attack()
method insidePokemon.java
, such that- Its
level
increases by one during the attack. - We expect the following output:
- Its
- Create another Pokemon instance in the
main()
method, similar to howpika
is created.- You will need to name it something other than
pika
. - There are two constructors.
- Which will you use? Either is fine for now – depends if you can think of a name for your new Pokemon!
- Call the
printDetails()
method on your new Pokemon. - Call the
attack()
method 3 times on your new Pokemon. - Call the
printDetails()
method on your new Pokemon after the attacks.
- You will need to name it something other than
- Run the program each time you modify the code.
- It feels like we are “telling a story” in the
main()
method!
- It feels like we are “telling a story” in the
There are a lot of concepts at play here, even with such a small example.
We’ll dig into these in the next few lessons.
Visualising our Pokemons with Python Tutor
This tool is going to be useful, especially from now on as we dig into classes deeper.
We have a brief guide on using Python Tutor to visualise Java.
More specifically, here’s it being used to visualise this Pokemon example.
Another excellent explanation
- This video starts off very well in explaining how classes help us define custom data types.
- Again, for now:
- Just focus on the concepts.
- Don’t pay too much attention to the way the code was written.
- The way the code was written in this example is not representative of what we should do.
- We will understand the correct way when we learn constructors in more detail.
- For the purposes of this course, we will humbly rewrite the code as follows:
Get your hands dirty!
This exercise builds on the example in the above Mike Dane video.
It has the following differences:
- We make all
Student
fieldsprivate
.- This means we cannot access them the way he was accessing them in the
main()
method. - As a result, our constructor initialises all the fields.
- This means we cannot access them the way he was accessing them in the
- We will cover constructors in the next lesson – so don’t worry too much about this for now.
- We’ve added a
printDetails()
method, just so we can see a little better what’s happening.
Edit the code below:
- In the
main()
method, call theprintDetails()
method on each of the student instances. - Create another student instance, and call its
printDetails()
method.
Again, there are a lot of concepts at play here.
We’ll dig into these in the next few lessons.
For now, it’s enough to just try to appreciate what’s happening.
Why classes?
Do you remember structs from C? Well, classes are a massive improvement over them.
For the purpose of designing high-quality software, a class (and OOP in general) is much better since it allows for:
- Data hiding
- Methods
- Inheritance
- Polymorphism
The features above probably don’t mean much to you right now, but we will soon see how they help us create maintainable software:
- Natural way of thinking, close to human language.
- Protects programmers by hiding unnecessary details.
- Easy to modify existing code.
- The code is easy to extend with new functionality.
- It encourages conciseness.
- It encourages reusing code.
The Person running theme
The main running theme for the next few lessons will be around the idea of the Person class.
However, we will visualise the idea of a blueprint and instances in a simplified way that better resembles what happens in the program.
Instances are ultimately just stored data that we can manipulate in our program.
All the information corresponding to one instance is stored in the computer’s memory, just like any other data.
We can imagine the information for each instance being written on a piece of paper, and then stored in memory.