LogoDart Beginner Tutorials

Building Your Pets Class

Learn object-oriented programming by creating a DigitalPet class to encapsulate your pets data and functionality.

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.