OOPs in Dart

Let’s dive into Object-Oriented Programming (OOP) in Dart! OOP is a way of writing code that organizes it around "objects" rather than just functions or logic. Think of objects as real-world things—like a car, a dog, or a book—that have properties (like color or size) and behaviors (like driving or barking). Dart, the language used for Flutter and more, supports OOP beautifully. I’ll break it down into simple topics and sub-topics with easy explanations and examples.


1. Basics of OOP

OOP revolves around four main ideas: Encapsulation, Inheritance, Polymorphism, and Abstraction. Dart uses these to help you write clean, reusable code. Let’s start with the building block: Classes and Objects.

1.1 Classes and Objects

  • Class: A blueprint for creating objects. It defines what an object can have (properties) and do (actions).

  • Object: An instance of a class—like a real thing made from the blueprint.

Example:

dart

class Dog {
  String name = "Buddy"; // Property
  int age = 3;

  void bark() { // Behavior (method)
    print("$name says Woof!");
  }
}

void main() {
  Dog myDog = Dog(); // Creating an object
  print(myDog.name); // Output: Buddy
  myDog.bark(); // Output: Buddy says Woof!
}

Here, Dog is the class, and myDog is the object. The object gets its own copy of name, age, and bark().


2. Encapsulation

Encapsulation means keeping an object’s data safe by hiding it and only allowing access through methods. It’s like locking your phone—only you can unlock it with the right key (method).

2.1 Private Variables

  • Use _ (underscore) before a variable or method name to make it private to the class.

  • Access it using getters and setters.

Example:

dart

class Person {
  String _name = "Alice"; // Private variable

  // Getter
  String get name => _name;

  // Setter
  void set name(String newName) {
    _name = newName;
  }
}

void main() {
  Person person = Person();
  print(person.name); // Output: Alice
  person.name = "Bob"; // Using setter
  print(person.name); // Output: Bob
}

Here, _name is hidden, but we can still get or set it using name.


3. Inheritance

Inheritance lets one class "inherit" properties and methods from another class. It’s like a child inheriting traits from a parent.

3.1 Extending a Class

  • Use the extends keyword to inherit.

Example:

dart

class Animal {
  String type = "Unknown";

  void eat() {
    print("This $type is eating.");
  }
}

class Cat extends Animal {
  Cat() {
    type = "Cat"; // Override the property
  }

  void meow() {
    print("Meow!");
  }
}

void main() {
  Cat myCat = Cat();
  myCat.eat(); // Output: This Cat is eating.
  myCat.meow(); // Output: Meow!
}

Cat inherits type and eat() from Animal and adds its own meow().

3.2 Overriding Methods

  • You can change an inherited method’s behavior using @override.

Example:

dart

class Animal {
  void sound() {
    print("Some sound");
  }
}

class Dog extends Animal {
  @override
  void sound() {
    print("Woof!");
  }
}

void main() {
  Dog myDog = Dog();
  myDog.sound(); // Output: Woof!
}

The sound() method in Dog overrides the one in Animal.


4. Polymorphism

Polymorphism means "many forms." It lets you use a parent class type to refer to a child class object, and the correct method will still run.

Example:

dart

class Animal {
  void sound() {
    print("Generic sound");
  }
}

class Dog extends Animal {
  @override
  void sound() {
    print("Woof!");
  }
}

class Cat extends Animal {
  @override
  void sound() {
    print("Meow!");
  }
}

void main() {
  Animal myPet1 = Dog(); // Polymorphism
  Animal myPet2 = Cat();
  myPet1.sound(); // Output: Woof!
  myPet2.sound(); // Output: Meow!
}

Even though myPet1 and myPet2 are of type Animal, they call the overridden methods from Dog and Cat.


5. Abstraction

Abstraction hides complex details and shows only what’s necessary. It’s like using a TV remote—you don’t need to know how it works inside, just the buttons.

5.1 Abstract Classes

  • Use the abstract keyword. You can’t create objects from abstract classes, but they can be inherited.

Example:

dart

abstract class Shape {
  void draw(); // Abstract method (no body)
}

class Circle extends Shape {
  @override
  void draw() {
    print("Drawing a circle");
  }
}

void main() {
  Circle myShape = Circle();
  myShape.draw(); // Output: Drawing a circle
}

Shape is abstract, so we implement draw() in Circle.


6. Constructors

Constructors are special methods that run when an object is created. They set up the object.

6.1 Default Constructor

  • Automatically provided if you don’t define one.

Example:

dart

class Car {
  String model;

  Car(this.model); // Short constructor syntax
}

void main() {
  Car myCar = Car("Toyota");
  print(myCar.model); // Output: Toyota
}

6.2 Named Constructors

  • Extra constructors with names for flexibility.

Example:

dart

class Car {
  String model;

  Car(this.model); // Default constructor

  Car.named(String customModel) {
    model = "Custom $customModel";
  }
}

void main() {
  Car car1 = Car("Honda");
  Car car2 = Car.named("Ford");
  print(car1.model); // Output: Honda
  print(car2.model); // Output: Custom Ford
}

7. Interfaces and Mixins

Dart doesn’t have a separate interface keyword, but any class can act as an interface. Mixins add reusable code.

7.1 Implementing an Interface

  • Use implements to follow a class’s structure.

Example:

dart

class Flyer {
  void fly() {
    print("Flying...");
  }
}

class Bird implements Flyer {
  @override
  void fly() {
    print("Bird is flying!");
  }
}

void main() {
  Bird bird = Bird();
  bird.fly(); // Output: Bird is flying!
}

7.2 Mixins

  • Use with to add extra behaviors.

Example:

dart

mixin Swimmer {
  void swim() {
    print("Swimming...");
  }
}

class Duck extends Animal with Swimmer {
  Duck() {
    type = "Duck";
  }
}

void main() {
  Duck duck = Duck();
  duck.eat(); // Output: This Duck is eating.
  duck.swim(); // Output: Swimming...
}

Swimmer mixin adds swim() to Duck.


8. Static Members

Static variables and methods belong to the class itself, not objects.

Example:

dart

class Counter {
  static int count = 0;

  Counter() {
    count++;
  }

  static void showCount() {
    print("Total objects: $count");
  }
}

void main() {
  Counter c1 = Counter();
  Counter c2 = Counter();
  Counter.showCount(); // Output: Total objects: 2
}

count and showCount() are shared across all objects.


Summary

Here’s what we covered:

  1. Classes and Objects: Blueprints and instances.

  2. Encapsulation: Hiding data with private variables, getters, and setters.

  3. Inheritance: Reusing code with extends and overriding.

  4. Polymorphism: Using parent types for child objects.

  5. Abstraction: Simplifying with abstract classes.

  6. Constructors: Setting up objects.

  7. Interfaces and Mixins: Adding structure and reusable behaviors.

  8. Static Members: Class-level data and methods.

OOP in Dart is all about making code organized, reusable, and easy to understand. Practice these with small projects—like a pet simulator or a simple game—and you’ll get the hang of it! Let me know if you want more examples or help with anything specific.

0
Subscribe to my newsletter

Read articles from Singaraju Saiteja directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Singaraju Saiteja
Singaraju Saiteja

I am an aspiring mobile developer, with current skill being in flutter.