Welcome to Part 5! So far, our digital pet simulation has worked, but our code is starting to get a bit messy. Time to organize! This recipe will teach you the fundamentals of object-oriented programming (OOP) in Dart by creating a
DigitalPet
class. This will greatly improve our code's structure and make it much easier to maintain and extend.
Problem: Our code is becoming increasingly difficult to manage. We need a better way to organize the data (hunger, happiness, name) and the functions (feed, play, timePasses) related to our pet.
Solution:
We'll create a
DigitalPet
class to encapsulate our pet's data and behavior. This will make our code cleaner, more modular, and easier to understand.
Step 1: Creating the DigitalPet Class
Let's create a new class called
DigitalPet. A class is a blueprint for creating objects. In our case, each
DigitalPet
object will represent a single digital pet.
class DigitalPet {
String name;
int hunger;
int happiness;
DigitalPet(this.name, this.hunger, this.happiness); // Constructor
}
This code defines a class with three instance variables:
name,
hunger, and
happiness. The constructor
DigitalPet(this.name, this.hunger, this.happiness);
is a shorthand way to initialize these variables when creating a new
DigitalPet
object.
Step 2: Encapsulation with Private Variables
To prevent direct access and accidental modification of the
hunger
and
happiness
values, let's make them private using an underscore
_
prefix:
class DigitalPet {
String name;
int _hunger;
int _happiness;
DigitalPet(this.name, this._hunger, this._happiness);
}
Now, these variables can only be accessed and modified through methods within the
DigitalPet
class itself.
Step 3: Adding Getters
To allow controlled access to the private variables
_hunger
and
_happiness, we'll create getter methods:
int get hunger => _hunger;
int get happiness => _happiness;
These getters allow us to retrieve the values of
_hunger
and
_happiness
without directly accessing the private variables.
Step 4: Moving Existing Functions into the Class
Let's move the
feed,
play,
timePasses, and
displayStatus
functions into the
DigitalPet
class. These functions now act as methods of the
DigitalPet
class:
void displayStatus() {
print("--- ${name}'s Status ---");
print('Hunger: $_hunger');
print('Happiness: $_happiness');
print('-------------------------');
}
Future<void> feed() async {
// ... existing feed function code ...
}
// ... similar for play and timePasses ...
Now, these functions operate directly on the
_hunger
and
_happiness
variables of the specific
DigitalPet
instance they are called on.
Step 5: Creating and Using a DigitalPet Object
In your main function, we now create an instance of the DigitalPet class:
void main() async {
// ... (rest of the main function remains almost identical) ...
DigitalPet myPet = DigitalPet(petName, 5, 5); //create DigitalPet object
while (true) {
myPet.displayStatus(); // Use the displayStatus method
// ... (rest of the main function remains almost identical) ...
await myPet.feed(); // Use the feed method
// ... (rest of the main function remains almost identical) ...
}
}
We've replaced direct access to
hunger
and
happiness
with calls to the
myPet
object's methods.
Congratulations! You've successfully refactored your code using object-oriented programming principles! Your code is now much more organized and maintainable.
Next Steps:
In the next recipe, we'll focus on enhancing your pet's status display, learn about string interpolation, importing libraries, and using the
clamp
method for improved data management.
