Welcome to Part 5! In the previous parts, you built a functional digital pet simulator. Now, we'll elevate your code by introducing object-oriented programming (OOP) concepts. We'll encapsulate our pet's attributes and behaviors within a
DigitalPet
class, making the code more organized, reusable, and maintainable.
Step 1: Creating the DigitalPet Class – Encapsulation#
Let's create a class to represent our digital pet. This class will hold the pet's attributes (like name, hunger, and happiness) and methods (like
feed,
play, etc.). Replace your existing
feed
and
play
functions and the content of your
main
function with the following code:
import 'dart:io';
class DigitalPet {
String name;
int _hunger; // Private variable for hunger
int _happiness; // Private variable for happiness
// Constant values for the maximum and minimum stat values
static const int MAX_STAT_VALUE = 10;
static const int MIN_STAT_VALUE = 0;
DigitalPet(this.name)
: _hunger = 5,
_happiness = 5; // Constructor to initialize hunger and happiness
int get hunger => _hunger; // Getter for hunger
int get happiness => _happiness; // Getter for happiness
void displayStatus() {
print("--- ${name}'s Status ---");
print('Hunger: $_hunger');
print('Happiness: $_happiness');
print('-------------------------');
}
Future<void> feed() async {
print('$name is eating...');
await Future.delayed(Duration(seconds: 2));
_hunger = (_hunger - 2).clamp(MIN_STAT_VALUE, MAX_STAT_VALUE);
_happiness = (_happiness + 1).clamp(MIN_STAT_VALUE, MAX_STAT_VALUE);
print('$name finished eating! Hunger decreased, happiness increased.');
}
Future<void> play() async {
print('$name is playing...');
await Future.delayed(Duration(seconds: 3));
_happiness = (_happiness + 3).clamp(MIN_STAT_VALUE, MAX_STAT_VALUE);
_hunger = (_hunger + 1).clamp(MIN_STAT_VALUE, MAX_STAT_VALUE);
print('$name finished playing! Happiness increased, hunger increased.');
}
}
void main() async {
stdout.write('What would you like to name your pet? ');
String? petName = stdin.readLineSync()?.trim();
petName ??= 'Buddy';
print('Hello, $petName!');
DigitalPet myPet = DigitalPet(petName);
await myPet.feed();
await myPet.play();
myPet.displayStatus();
}
Notice how the hunger and happiness variables are now private (_hunger,
_happiness), and we use getters (hunger,
happiness) to access them. This is a fundamental OOP principle of data encapsulation – protecting the internal state of the object. The
clamp
method ensures that the hunger and happiness values stay within the 0-10 range. The
static const
values for minimum and maximum values are used for better code readability and maintainability. The constructor (DigitalPet(this.name)) simplifies object creation.
Step 2: Adding More Methods – Expanding Functionality#
Let's add more methods to our
DigitalPet
class to make it more complete. Add these methods inside the
DigitalPet
class:
Future<void> timePasses() async {
print('Time passes...');
await Future.delayed(Duration(seconds: 1));
_hunger = (_hunger + 1).clamp(MIN_STAT_VALUE, MAX_STAT_VALUE);
_happiness = (_happiness - 1).clamp(MIN_STAT_VALUE, MAX_STAT_VALUE);
if (_hunger >= MAX_STAT_VALUE) {
print('$name is very hungry!');
}
if (_happiness <= MIN_STAT_VALUE) {
print('$name is very sad!');
}
}
bool needsAttention() {
return _hunger >= MAX_STAT_VALUE || _happiness <= MIN_STAT_VALUE;
}
The
timePasses
method simulates the passage of time, increasing hunger and decreasing happiness. The
needsAttention
method checks if the pet needs immediate care. This demonstrates method functionality within a class structure.
Step 3: Updating the main Function – Using the Class#
Now, modify your
main
function to use the
DigitalPet
class and its methods. This refactors the code, making it more structured and readable. Replace your
main
function with this improved version:
void main() async {
stdout.write('What would you like to name your pet? ');
String? petName = stdin.readLineSync()?.trim();
petName ??= 'Buddy';
print('Hello, $petName!');
DigitalPet myPet = DigitalPet(petName);
await myPet.feed();
await myPet.play();
await myPet.timePasses();
myPet.displayStatus();
if (myPet.needsAttention()) {
print('Warning: ${myPet.name} really needs your attention!');
}
}
This streamlined version utilizes the methods of the
DigitalPet
class, showcasing better code organization and readability.
Congratulations! You’ve successfully implemented object-oriented programming principles, creating a well-structured and reusable
DigitalPet
class.
What's Next?#
In the final part, "The Complete Digital Pet Simulator: Bringing It All Together," we'll integrate all the features we've developed into a complete, interactive pet simulator with a menu-driven interface. Get ready for the grand finale!
