in this video we are going to take a look at making our classes immutable and meaning that
they can't be changed once they are created now the techniques are valuable if
you want instances on your class to be immutable but also using some of the
techniques in immutable classes is a great way to increase encapsulation
and reduce errors even if your going to allow external code to modify your class
instances now we are going to use the location class from the previous videos
challenges as an example and that might lead you to think that its only a game
its my code why would I want to protect the object from external modification
to really answer that question, what you want to do is to consider modern software that supports
third-party extensions or plug-ins now if your using IntelliJ IDEA for example support
other languages such as Python by providing the plugins that can be
developed by third parties now many modern browsers as another example that
have support for third-party plug-in for years and even games allow external developers to
create additional rooms or levels so another example is Microsoft office which
provides access to its objects to macros written in VBA now all of these
examples exposed to programs inner objects to external developers who
don't have access to the source code and therefore they don’t know the
implications of changes they might make two objects if they are allowed to do that
so reading the API documentation will help them but it's reasonable for them
to assume that if they're permitted to change fields and properties then they cab go ahead
and do so now we briefly discussed one technique to be used in the location
class which was the getExits getter for the exits map which you can see on line 33
so rather than return the exits object directly which would expose it to the
potential for being changed externally we created a new HashMap object that
contains all the elements of exits and return that so external code that needs
to use the exits when we displayed the list of available exits to the player in the main
class to do so there's no chance of changing our internal map as it turns
out we could in fact returned the list of available exits as a string which
maybe more convenient for our particular program but that would have
reduced flexibility in it that kind of approach is taken as a rule
the we have to consider all the possible uses that external code may actually want to
make from our map so the approach taken here doesn't restrict external code from
doing when it needs to do with a map it just prevents that from changing our map
which is obviously good from our point of view now the second technique that we’ve used to make our
fuels private and final lines 10, 11, and 12 you can see that, and that means that once
they have been set that can't be changed now you may argue that final was unnecessary
here because if the fields are private then they can’t be accessed externally anyway while
that's true the use of final does provide two benefits firstly it makes it
clear to anyone reading the code that the field shouldn't be changed and we didn't
forget to write a setter and also ensure that we don’t inadvertently change the fields
if we change the code in the location class at some time in the future, now the first
point also hints at the third technique that was employed here the fact that we
didn't provide setters for the id and description fields now as yo see
throughout this course IntelliJ has got an option to generate
getters and setters and it can be tempting to get into the habit of
automatically generating both setters and getters just in case you might need them
down the track but that's actually a bad habit to get into so its much better to only
provide a setter if the class actually now it might appear first glance that the
location class does in fact need to setter for the exits available at each location and
we did indeed use it to give each location its exits takes and it may even
made sense to leave the setter in our class so that if someone else wanted to
extend the game they could add new exits from existing locations to the new ones
they add but we discussing how to create an immutable classes so will look at a
technique for setting the initial exits then preventing further change so
if a class field or elements of a immutable class like a list or a map is to be
set only once and never changed again then what it needs to be done and
where it needs to be set is in the constructor so what we're gonna go ahead
and do now is modified the class constructed to accept the map object
and will change our constructor signature and assign the passed map to our
class fields and this means that we can delete the addExits method all
together so what we'll do is come back to the constructor
and in the location id and the string is correct as is we don’t need to change does
but we want to add our exits so do that we would put in…which is our type of map…
for our exits will call it exits and will change this, we don’t
anymore need to create a new instance anymore this will just be a case of setting it to exits, and the next line, line
18 still assigns our ability to quit out of a particular location
and consequently we no longer need to use or have the addExit anymore because
we are getting all the exits basically when the objects constructed so I’m going to comment that out as well, now the class
looking at this now you might think we'll this classes is now immutable but in
fact there is one more change we need to make it truly immutable and to demonstrate
why we haven't achieved immutability, what I’ll do is modify the main
method to use a change location class so that we can run the program and
we can see what the problem is the first change we need to do going back to main now
we are getting those errors as you can see there is we need to use a temporary maps
so that we can set up with the correct exits for each location and we pass those
to the location constructor
so the first problem we aren’t gonna address yet the line 21 through 26 will start
by setting up these locations and what we need to do is create a temporary
map which is going to be exits because we now passing that as a constructor
so we are gonna do map string integer and will call that temp…
and obviously making that change to
each of the remaining lines will be quite tedious because obviously I’ve replaced there on line 29 on line 31 would
be so I take it out there now, so would be quite tedious to do that especially we had a
full list of locations in our program but fortunately both IntelliJ products
and IDEA products and Python support regular expressions now we are gonna cover
regular expressions in more detail later in the course so don't worry about them
too much at this stage but this quick demonstration will give you an idea of
how useful it can be now we can't use a normal search and replace because the
location number appears on each line and of course with only 5 locations
we could just do 5 searches and replace, but the full game will have many more than 5 locations
so what we can do is use the Find and Replace for the regular expressions
so go to the Edit menu and choose find then replace and I think its
control+ r on a PC and you can see to the right command R is the key stroke
to the shortcut cut opens up this little find window then you need to make sure
that the regular expression is actually checked because that's an indication that
we're typing a regular expression what we want to do is change this so I’m going to type
locations…
and you can see the
match there on the screen
IntelliJ is showing you what its matching based on what we've typed so we wanna
replace all of that now with the syntax that we got on line 29 so change that with
temp…and the rest that are not highlighted on line 31 through 33 is still going to be
valid as you can see from there thats pretty cool you can see how IntelliJ
based on the expression that we've typed in is smart enough to figure out
what we're trying to achieve with a regular expression and we can now do a
replace all and that's all done and we haven’t have to type all these things manually so that's got our
solution so the only other thing we want to do here is we want to make sure that
we are new setting tempexit to new HashMap after each room
so that the previous rooms exits aren’t included in that new room so
I’m just gonna copy and paste that before each section for each room, location 1,2,3,4,5 and
6 now, and just a typo there, we won’t need it because that there because that was the
room so our main room on room 1 is location 1 has got the for exits so onsequently we've got like location 1
location 2, location 3, location 4, location 5 is now all defined
for the various exits that are valid for that so all that's left now is
to move the lines 21 to 26 into the appropriate area after it's exits
have been defined and to pass the tempexits map to the constructor so we gonna do
this we are gonna select each one we’re gonna start on room 1 their, and ill do room 0 separately because that's a
special case
and we should be able to do is use another search here we don’t need a regular expression for it to
quickly make a change just the save us having to type
so we can select that and come up here and we could just do a search for right bracket, right bracket
turn off the regex, semi colon, replace that with
comma… so now if I do a replace all that should fix it and obviously on line
0 I need to fix it up shortly which ill do and we should be good to go and be careful when
you are selecting when you are doing a replace all that your not replacing more
than you thought what I could probably should have done is selected that range in here
you can actually click on in selection that would only do the changes that were
valid for that selection rather than the whole file so keep in that mind when your
doing your searches, alright do a command R to close it
ok so the last thing we need to do now, so
we’ve got our code working for the various news the only special case we
need to do is for the first room and what will do there, I’m just going create that there for the first time, and I’m just going to take a
copy and paste it in there for our room so consequently now we should be good to go
and we got an error here, and I think this was the mistake I made when I did that global search
and replace that why its always handy to use it in selection to make sure you only
select certain things not the whole thing so we just need to remove that, so we are almost
done at this point, if we run the program we should find everything
still works so I should be able to type in north, south, north, go west, quit now ,that's alll
working
but we still do have one problem that exposes our location class and just to show
you what I mean come down here to the while loop and just after the printing out of the location
description we could do something like this temp… so we run that, so if we go north, we now
suddenly got no south that's because we managed to remove it from the
class that's calling our location class was able to delete part of the map so had we
created a new map for each location instead of reusing tempExit we could
have wrecked havoc on the exits for all locations and
not just the last one and the reason we're able to do this is because we
still had a reference to the exits map for location 5 which of course was
the forest so to cure the problem we need to use the same technique as we did for the
get exits method only now we're going to apply it to setter instead of to a getter
so what I mean by that, go back to our location and in our constructor on line
17 what we gonna do is change that
to be equal to a new HashMap exits and if we run this, just to confirm it works, and we go north again
now, now get correctly our south even though back in this code here, we’ve added the code to remove s from
the tempexit it hasn't affected our location class at all that's because we've
created a new HashMap based on this HashMap that was passed to us so at this point you
could say that the class is now fully immutable once an instance is
created it can't be changed and again this means it could be used as a key to
a map with no ill effects although I did this to really demonstrate to techniques
not because of any particularly good reason for making our location a key
even though we don't want to use it as a key though these techniques have
resulted in a very secure class that fully encapsulates its fields
depending on the functionality class must provide it may not be possible to
employ all these techniques they should certainly be considered and you should
be doing that when you're creating classes considering these things
in as many of them as possible used in order to increase encapsulation and of
course reduce errors as a result now there is one step that oracle recommends
when creating fully immutable classes and I'm going to open up the link here
in a browser, link will be in the Resources section, you see the 4 points
that are covering their so we've covered point one don’t provide setter methods
those no setters in our class, part 2 is to make all fields final and private
and we’ve done that so point two is done with us as well we do have references to immutable object the
exits map and we've removed our exits as method that might modified the map and we also
change the constructor and getter exits so that we're not sharing references to the map
looking at that point for is also covered as well and of course we did
part 3 as well by declaring the classes final looking back on this again
we didn't defined the classes as final but we defined all are variables so
it's not just overriding methods the can prevent our class from being immutable, adding new
methods that expose our map will also do so and obviously hence instructions
should really read here on part three is probably more accurate to say don't allow
a class to be sub classed and that's actually where the two recommendations
were achieved as we saw in the previous section making a class final prevents
it from being sub class so the more sophisticated approach of making the
constructor private also prevents the class from being sub classed as well okay so
I'm going to end the video here in the next video we are just going finalizes the
discussion about immutability and I'm gonna come up with another challenge so
I'll see you in the next video