Hi everyone!
In the last lesson we talked about chaining constructors to give ourselves more options
for creating instances of our classes.
While chaining constructors helped us in some ways, it introduced a problem where we needed
a specific order to create our instance, so in this lesson I want to show you another
technique for creating instances in Java using the builder pattern.
We'll also discuss a bit about what patterns are, and some good techniques for designing
your class builders.
That's coming up.
First, what are design patterns?
We'll cover design patterns in depth later in another series, but for now the quick 60
second version is patterns are a standard way of addressing common programming problems
with an identified solution.
The solution is based on the experience of other developers before us, and is usually
recognized a good solution to a known common problem.
The beauty is, when we say builder pattern, everyone should know we're talking about a
specific solution and they should already have a good idea for how it works.
Patterns are a common language we use to communicate with other programmers.
This makes it easier to talk to others about how a section of our code functions.
What is the builder pattern?
So what does the builder pattern do?
The builder pattern is a pattern that allows us to separate the construction of a more
complex class, from the representation of the class.
Basically that means we're creating a class who's sole purpose in life is to create the
class we want.
Imagine we're asking someone to make a PC for us.
We would tell them the amount of RAM to use, the hard drive size, the CPU speed, and so
on.
The person building our computer would take our list of specifications, and turn that
into a computer to hand back to us.
The builder would also tell us when we've asked for something that can't be built.
Like if we specify a SCSI hard drive, and a SATA controller.
That's how it would work in real life.
Here's how it works in software.
We create a class that contains all the state variables we need to set to create a functioning
object.
We have a setter for each of these values.
You'll notice we drop the "set" word from the method name.
This is a departure from how we normally do getters and setters.
It's because the builder uses the Fluent Interface idiom.
The Fluent Interface idiom just makes the code more readable when you're using the class.
The interesting part is the setter returns a builder object holding the value, and any
other previously set values.
This allows us to chain our calls together.
When we're done, we call the build() method on the builder.
That returns us an instance of the object we want, with everything configured.
If the builder can't build our instance, it should error out and not create the instance.
In Java the standard way of doing this is to throw an exception.
Exceptions are a longer topic we'll cover in depth.
For now we'll just throw exceptions using this code.
IllegalStateException is the exception we throw when someone is trying to create our
class in an illegal state.
Exceptions are a longer topic we'll cover in depth in a later lesson.
Just know this is causing an error, and prevents the instance from getting created.
How does this help?
Well for starters, order is no longer important.
We can specify our attributes in any order.
In our football game, we can specify the home team, then the stadium, then the starting
position, and then the away team.
Or we can specify them in another order.
In the end, our builder will give us a usable instance or an error.
We'd use this over chaining constructors because we can mix around the order of our state.
It also allows us to prevent object creation in an inconsistent state.
We can't create a game instance where only one team is specified.
We can't forget to position the ball on the 35 yard line.
The builder will not return an instance until it has all the information needed to create
the instance in a usable state.
The builder pattern would be overkill if you have only a few attributes to set.
For example, we probably would not use a builder pattern to create an object with three attributes.
Chaining is a simpler solution for simple classes.
The builder pattern is for larger, more complex class construction.
Implementing the builder pattern Let's create a builder for our football game.
We'll create the class with all the parameters we need for the game class.
If we want to give any of these attributes default values, we'll do it in the builder.
Each setter sets the value, then returns the GameBuilder instance.
Then we provide a builder method.
This method first checks we have all the information we need to build the instance.
If we cannot create the instance in a useable state, we'll throw an IllegalStateException.
Finally we'll create the instance in one go, and return the result.
We will also create a single constructor for our class that accepts the builder as a parameter.
This makes sure users of our class use the builder, one way or another.
You can create an instance of your class with this code.
This calls the build() method on the builder.
This is the preferred way to use the builder pattern.
Another way to do it, is to populate a builder, and then pass that to the class.
This way is less desirable, because it's harder to read.
The only reason you can do it this way is because we need to create a single constructor
for our game object.
This enforces object creation through the builder.
The constructor with a builder argument should be the only way to create your instances.
This prevents sneaky developers from trying to create instances without using the builder.
We really want anyone using our class to use the builder.
In order to completely prevent instance creation without using the builder, we need make the
builder part of the class.
We can define a class inside a class.
So our builder would be a static class inside our class.
In this case, you'd make the constructor private.
This way we can only create new instances from the builder.
There is no constructor exposed.
Thanks for watching!
That was a longer lesson, so if you have any questions let me know in the comments.
New lessons come out every week, so make sure you subscribe.
You don’t want to miss a video!
And with that, I’ll see you in the next tutorial!