So in the previous video, we started work on our challenge solution.
So I went through and we've introduced the basic concept of the ISaveable interface,
as well as creating a class,
a player class that actually implemented that interface.
And as you saw that the actual methods that we created will take
any class that implements the ISaveable interface.
So, player was one example, but we can actually create a monster class for
the game and persist that data, the data relating to that, in the same way.
Monsters are very similar to the players, but they don't have weapons,
just their natural claws and fangs as we're gonna do here.
So, the point about this is,
by creating this other class, you can still use these other methods and
create some pretty cool code that actually saves the state of the monsters.
So, lets do that now.
So I'm going to create a new class, Monster, and it's going to implement.
Implements the ISaveable interface.
And we're gonna start off having a name, private String name,
private int hitPoints, how strong the creature is in other words.
private int strength, like so, and I'm going to create a public
constructor that's going to accept those three parameters.
And so we can set them like so.
And we're going to create some getters, actually we don't need getters, we
actually need setters, because we're gonna do the setting setup in the constructor.
So, I'll create the getters for each of those.
So we can access those.
Okay, so let's create the toString.
So I've selected that and there's different options here,
the one I normally use is this one here.
The first one string [INAUDIBLE] which was the one that was selected originally, but
I just wanted to point out that you can actually experiment and
try some other things if you wanna do that.
But that will be the working fine for this example, so we're gonna click on that.
And that's our toString, which we'll see and use later.
And of course, the last two things we need to create now in this class,
or override, is the two methods, the write and read.
So we're gonna go down to Implement Methods,
in our Generate, select both of them.
And we've now got the list, and you can see it's using the generic lists now,
which is good.
So let's actually start off by creating the write method, so
that's going to be arrayList of strings again.
values = new ArrayList,
like so, values.add(0,
this.name).
I could have used a getter there if I wanted to,
.add(1, this.hitPoints).
values.add(2, this.strength).
And return values.
Like so, so that's our write method.
Very similar to the other method we wrote in the player class with the same name,
but of course, we've got one less full.
We haven't got a weapon for the monster.
And likewise, the read is gonna be pretty much the same.
If savedValues is not equal to null, and
savedValues.size is > 0, then and only then,
we're going to actually try and retrieve the [INAUDIBLE].
So this time, .name = savedValues.get(0).
this.hitPoints = Integer.parseInt().
And that's going to be savedValues.get(1), and
this.strength = Integer.parseInt(savedValues.get(2)).
So, and that's truly it.
So again, we are still implementing the write and read methods for
this class because we implemented the interface.
This code could be completely different if we wanted it to be.
But in this case, it's pretty identical to what was in the player class.
I mean, there's one less field to actually save and then ultimately load.
And then intents of going back and running this, we can go back to our main method.
And we could do something like Saveable,
ISaveable werewolf = new Monster("Werewolf"),
and hit points, 20, strength, 40, maybe?
We can print out the werewolf.
And we can also save the object.
saveObject(werewolf), just to see what actually happens.
And I'll take out this load here now, so we don't go through that again.
So we can actually check it, cuz we did that at the end of the last video.
And we'll actually run this.
And you can see now we've got monster now because werewolf hit points equal 20,
strength equals 40.
Saving werewolf to storage device, saving 20 to storage device cuz werewolf was
obviously the name, 20 was the hit points, and 40 was the strength.
So that's working as well, so you can say that there are obvious advantages to this
ISaveable interface, in that we're guaranteeing what's a contract to confirm
that if a class is implementing this interface, it has to implement that code.
So it's a way for you to make sure that those particular methods are overwritten,
so that the actual functionality that is needed for
that class is actually written, and it doesn't fall back to the super code,
the code that would be in a base class if you were using Inheritance.
The other thing I wanna point out, just close this down.
If you go back up here to where we were with printing out the object,
what we can't really do here so I'll actually create a new object but
what we can't do is we can't do werewolf.getStrength.
Obviously, we get an error and of course going back here though to monster,
we actually have got a method.
We've got a getter, we set up a getter for get.strength, but it's not working.
It's not working in there.
Now if you want to actually, if you know that this is the monster class, and
we know that because we've implemented that here.
We've actually used that when we're instantiating a new object.
And you actually want to use the get.strength, and what you have to do is
do something a little bit different to what you've done before.
But you're actually printing it out, we'll do something like this, we'd actually do,
let's just assume that line there we wanted to print it out, and so
we got to print it out.
That's obviously still not gonna work like the way it is there now, but
what we can actually do, is actually do this, we can actually put monster.
Werewolf, but get.strength like so, we need to put a bracket there as well.
Once we do that, it's now valid, because what we're doing is we're casting it,
we're actually saying this,
yes we know that this base class will use the ISaveable interface.
But when it comes time to print it out, what we're saying is now this is actually
the monster class, and remembering that we're implementing the interface but
it still actually is the monster class.
So we're doing that when we run this, it's the code is now valid and
we can actually go ahead and do that.
So I can actually change that now and just confirm.
We can put something like.
Like so, and if we run it.
You can see it's actually working there, Strength = 40.
So that's how you get around that,
the fact that you actually declared to this in an interface.
But if you still wanna get access to it and get access to specific
methods that are actually in the actual class, in this case, the monster class.
That's actually how you'll do it with a class.
Remember again,
the other thing you can do if you wanted to, you can actually just come back here.
We can literally just put the code in there in which case we can then do
werewolf.getstrength, and that would actually work.
So it all depends on how you actually go ahead with the declaration, whether you
decide to actually do as I'm showing on the screen there, if I just undo this now.
Okay, back to the ISaveable interface.
So it can be a little bit confusing in deciding when to declare an instance as
the class.
In this case, play, in this case, monster or player or when you know using ISaveable
interface when actually declaring the instance like here is the interface.
Generally speaking, it depends on what you're going to do with the instance.
So if you wanted to declare a variable that can hold objects of different types,
then it would have to be the type of the common interface.
But if you want to access methods that exist in the class like we wanted to do in
the case of monster, we wanted to get access to get.strength, but
they're not part of the interface itself.
Cuz obviously you go back to interface, there's no get.strength in there.
So if we wanted to do something like you saw me do here,
then the object will have to be declared as the class type itself,
unless you wanna get around it by using a class like you saw there.
Generally speaking, where there's no strong reason for using the class type, so
in this case there isn't really a strong need for us to use the monster class type.
Because we've got these generic methods for reading and writing, and
we can access those in a similar way.
So that being the case, generally,
you'll probably wanna declare it using the interface.
And that really is, I do anyway, because that keeps your code more generic and
makes sure you're getting the best out of using the interfaces.
You can always cast the instance to the interface or class type as necessary.
Keep that in mind as well.
Also notice that parameters to methods that have been declared as the interface
type are automatically cast from the class type for us, which is pretty cool.
So, Java does some of that work for you, to make sure that that's actually there so
you can sort of move to and fro with the declaration being an ISaveable.
Or if you're actually doing an, in this case,
actually using the Monster class itself.
Okay, so that's interfaces.
I hope you got a lot out of that.
And I'll end the video here now, and I'll see you in the next video.