Dart OOP Cheat Sheet 2024: An Amazing Refresher for interview

Dart OOP Cheat Sheet

Written and reviewed by: 

SHARE

Table of Contents

Download Dart OOP Cheat Sheet PDF Free

Subscribe to our newsletter to download the PDF for free! We’ll send the PDF straight to your inbox.

1. Classes and Objects

Defining a Class

 
A class is a blueprint for creating objects and encapsulating data and behavior. It typically includes fields, constructors, and methods.
				
					class Animal {
  String name;
  int age;

  // Constructor
  Animal(this.name, this.age);

  // Method
  void makeSound() {
    print('$name makes a sound.');
  }
}

				
			

Creating an Object

 

An object is an instance of a class, representing a specific entity with defined attributes and behaviors. You create an object using the new keyword or by calling the class constructor directly.

				
					void main() {
  Animal cat = Animal('Cat', 2);
  cat.makeSound(); // Output: Cat makes a sound.
}

				
			

2. Inheritance

Extending a class

 

Inheritance allows a class (subclass) to inherit properties and methods from another class (superclass). This promotes code reuse and establishes a natural hierarchy.

				
					class Dog extends Animal {
  String breed;

  Dog(String name, int age, this.breed) : super(name, age);

  @override
  void makeSound() {
    print('$name barks.');
  }
}


				
			

Using the Subclass

 

Create an object of the subclass to use its properties and methods, including those inherited from the superclass. The subclass can also override superclass methods.

				
					void main() {
  Dog dog = Dog('Dog', 3, 'Labrador');
  dog.makeSound(); // Output: Dog barks.
}


				
			

3. Abstract Classes

Defining an Abstract Class

 

An abstract class cannot be instantiated and is meant to be subclassed. It can include abstract methods that must be implemented by subclasses.

				
					abstract class Shape {
  void draw();
}


				
			

Implementing an Abstract Class

 

Subclasses must implement the abstract methods of the abstract class. This enforces a contract for what methods the subclass should provide.

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

class Square extends Shape {
  @override
  void draw() {
    print('Drawing a square.');
  }
}

				
			

Using Abstract Class Implementation

 

Create objects of the subclasses to use the implemented methods, fulfilling the contract defined by the abstract class.

				
					void main() {
  Shape circle = Circle();
  Shape square = Square();

  circle.draw(); // Output: Drawing a circle.
  square.draw(); // Output: Drawing a square.
}

				
			

4. Interfaces

Defining an Interface

 

Any class can be used as an interface by implementing its methods in another class. Interfaces define a set of methods that a class must implement.

				
					class Flyable {
  void fly() {
    print('Flying');
  }
}

class Bird implements Flyable {
  @override
  void fly() {
    print('Bird is flying.');
  }
}


				
			

Using the Interface

 

Implement the interface in a class and provide definitions for its methods. This allows different classes to share common behavior.

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


				
			

5. Mixins

Defining and Using a Mixin

 

A mixin allows a class to inherit methods from multiple classes. This is used for code reuse in a way that is more flexible than single inheritance.

Use the mixin in a class to include its methods. Mixins can be used to add behavior to a class without affecting its inheritance hierarchy.

				
					mixin Swimmable {
  void swim() {
    print('Swimming');
  }
}

class Fish with Swimmable {}

void main() {
  Fish fish = Fish();
  fish.swim(); // Output: Swimming
}


				
			

6. Encapsulation

Private Members

 

Use an underscore (_) to make a class member private. This restricts access to the member, enforcing a controlled access mechanism.

				
					class Encapsulated {
  String _privateVariable = 'This is private';

  String get privateVariable => _privateVariable;
  set privateVariable(String value) => _privateVariable = value;
}


				
			

Using Encapsulation

 

Access private members via getters and setters. This provides a way to control how values are set or retrieved from class members.

				
					void main() {
  Encapsulated obj = Encapsulated();
  print(obj.privateVariable); // Output: This is private
  obj.privateVariable = 'New Value';
  print(obj.privateVariable); // Output: New Value
}


				
			

7. Static Members

Defining Static Members

 

Static members belong to the class, not instances of the class. They can be accessed using the class name and are shared among all instances.

				
					class StaticExample {
  static int counter = 0;

  static void incrementCounter() {
    counter++;
  }
}

				
			

Using Static Members

 

Access static members using the class name. This is useful for values or methods that should be consistent across all instances of a class.

				
					void main() {
  print(StaticExample.counter); // Output: 0
  StaticExample.incrementCounter();
  print(StaticExample.counter); // Output: 1
}

				
			

8. Constructors

Default Constructor

 

A default constructor initializes an object when it’s created. It can be defined explicitly or provided by default if no other constructors are present.

				
					class DefaultConstructor {
  DefaultConstructor() {
    print('Default constructor called.');
  }
}


				
			

Named Constructor

 

A named constructor provides multiple ways to initialize an object. This is useful for creating different types of constructors within the same class.

				
					class NamedConstructor {
  NamedConstructor.named() {
    print('Named constructor called.');
  }
}


				
			

Using Constructor

				
					void main() {
  DefaultConstructor obj1 = DefaultConstructor(); // Output: Default constructor called.
  NamedConstructor obj2 = NamedConstructor.named(); // Output: Named constructor called.
}


				
			

Redirecting Constructor

 

A redirecting constructor calls another constructor in the same class. This avoids code duplication by reusing existing constructor logic.

				
					class RedirectingConstructor {
  RedirectingConstructor() : this.named();

  RedirectingConstructor.named() {
    print('Redirecting to named constructor.');
  }
}

void main() {
  RedirectingConstructor obj = RedirectingConstructor(); // Output: Redirecting to named constructor.
}

				
			

9. Getters and Setters

Custom Getters and Setters

 

Define custom logic for getting and setting private variables. This provides a way to add validation or other logic when accessing or modifying variables.

				
					class CustomGetterSetter {
  String _name;

  String get name => 'Name: $_name';
  set name(String value) => _name = value;
}

				
			

Using Getters and Setters

				
					void main() {
  CustomGetterSetter obj = CustomGetterSetter();
  obj.name = 'Alice';
  print(obj.name); // Output: Name: Alice
}


				
			

10. Overriding Operators

Overloading Operators

 

Overload operators to perform custom operations with class objects. This allows instances of your class to use operators like (+) in a natural way.

				
					class Vector {
  int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector other) {
    return Vector(x + other.x, y + other.y);
  }
}

				
			

Using Operator Overloading

 

Use overloaded operators to combine objects in a meaningful way. This can make your class instances behave more like built-in types.

				
					void main() {
  Vector v1 = Vector(1, 2);
  Vector v2 = Vector(3, 4);
  Vector v3 = v1 + v2;

  print('v3: (${v3.x}, ${v3.y})'); // Output: v3: (4, 6)
}


				
			

11. Polymorphism

Using Polymorphism

 

Polymorphism allows you to use a subclass object where a superclass object is expected, enabling flexible and reusable code.

				
					class Animal {
  void makeSound() {
    print('Some sound');
  }
}

class Dog extends Animal {
  @override
  void makeSound() {
    print('Bark');
  }
}

void main() {
  Animal myDog = Dog();
  myDog.makeSound(); // Output: Bark
}

				
			

12. Covariant and Contravariant

Covariant Parameters

 

Covariant parameters allow overriding methods to accept more specific types than the original method.

				
					class Animal {
  void feed(Covariant Animal animal) {}
}

class Dog extends Animal {}

class Caretaker {
  void feed(Animal animal) {}
}

class DogCaretaker extends Caretaker {
  @override
  void feed(Dog dog) {}
}


				
			

13. Late Initialization

Using late Keyword

 

The late keyword allows you to initialize variables at a later point, ensuring they are non-null when accessed.

				
					class LazyInit {
  late String description;

  void initialize() {
    description = 'Initialized';
  }
}


				
			

14. Singleton Pattern

Implementing Singleton Pattern

 

The Singleton pattern restricts a class to a single instance and provides a global point of access to it.

				
					class Singleton {
  Singleton._privateConstructor();

  static final Singleton instance = Singleton._privateConstructor();
}

				
			

15. Type Aliases

Using Type Aliases

 

Type aliases allow you to create a new name for an existing type, improving code readability.

				
					typedef IntList = List<int>;

IntList numbers = [1, 2, 3]; // This is equivalent to List<int> numbers

				
			

16. Callable Classes

Creating Callable Classes

 

A class with a call method can be used like a function, enabling a more functional programming style.

				
					class Adder {
  int call(int a, int b) => a + b;
}

void main() {
  var add = Adder();
  print(add(2, 3)); // Output: 5
}


				
			

17. Built-in Mixins

Using Built-in Mixins

 

Dart provides built-in mixins like Comparable and Iterable to enhance class functionality.

				
					class Person with Comparable<Person> {
  String name;
  int age;

  Person(this.name, this.age);

  @override
  int compareTo(Person other) => age - other.age;
}


				
			

18. Deep Copy

Implementing Deep Copy

 

Deep copy creates a new instance of an object with the same values, avoiding references to the original object.

				
					class Person {
  String name;
  int age;

  Person(this.name, this.age);

  Person copy() => Person(name, age);
}

				
			

19. NoSuchMethod

Overriding noSuchMethod

 

Override noSuchMethod to handle method calls that don’t exist, enabling dynamic behavior in your classes.

				
					class DynamicClass {
  @override
  dynamic noSuchMethod(Invocation invocation) => 'Method not found';
}


				
			

20. Static Initialization

Static Initialization Block

 

Use a static initialization block to execute code when the class is first loaded.

				
					class Configuration {
  static final Configuration instance = Configuration._privateConstructor();

  Configuration._privateConstructor();

  static void _initialize() {
    print('Class loaded');
  }
}

				
			

21. Custom Exceptions

Defining Custom Exceptions

 

Create custom exception classes to handle specific error conditions in your code.

				
					class InvalidInputException implements Exception {
  final String message;

  InvalidInputException(this.message);

  @override
  String toString() => 'InvalidInputException: $message';
}

				
			

22. Final and Const

Using final and const

 

final and const are used for variables whose values won’t change, with const being compile-time constant.

				
					class Constants {
  final String name = 'John';
  static const int age = 30;
}

				
			

23. Interfaces and Abstract Classes

Combining Interfaces and Abstract Classes

 

Use both interfaces and abstract classes for a more flexible design.

				
					abstract class Drawable {
  void draw();
}

class Circle implements Drawable {
  @override
  void draw() {
    print('Drawing circle');
  }
}

				
			

24. Method Cascades

Using Method Cascades

 

Method cascades allow you to chain multiple method calls on the same object.

				
					class Builder {
  String content = '';

  Builder add(String part) {
    content += part;
    return this;
  }
}

void main() {
  var builder = Builder()
    ..add('Hello ')
    ..add('World');
  print(builder.content); // Output: Hello World
}

				
			

25. Generics with Constraints

Using Generics with Constraints

 

Generics can be constrained to specific types using the extends keyword.

				
					class Repository<T extends Animal> {
  void save(T entity) {
    print('Saving $entity');
  }
}

				
			

26. Utility Methods

Adding Utility Methods

 

Add utility methods to your classes for common operations, improving code organization.

				
					class MathUtils {
  static int add(int a, int b) => a + b;
  static int multiply(int a, int b) => a * b;
}

				
			

27. Fluent Interfaces

Implementing Fluent Interfaces

 

Fluent interfaces return this to allow method chaining.

				
					class QueryBuilder {
  String query = '';

  QueryBuilder select(String field) {
    query += 'SELECT $field ';
    return this;
  }

  QueryBuilder from(String table) {
    query += 'FROM $table ';
    return this;
  }
}

				
			

28. Immutable Classes

Creating Immutable Classes

 

Make classes immutable to prevent modification after creation.

				
					class ImmutablePoint {
  final int x, y;

  const ImmutablePoint(this.x, this.y);
}

				
			

29. Proxy Pattern

Implementing Proxy Pattern

 

The Proxy pattern provides a surrogate or placeholder for another object.

				
					class RealSubject {
  void request() {
    print('Real request');
  }
}

class Proxy {
  final RealSubject _realSubject = RealSubject();

  void request() {
    print('Proxy request');
    _realSubject.request();
  }
}


				
			

30. Composite Pattern

Implementing Composite Pattern

 

The Composite pattern allows you to compose objects into tree structures to represent part-whole hierarchies.

				
					abstract class Component {
  void operation();
}

class Leaf extends Component {
  @override
  void operation() {
    print('Leaf operation');
  }
}

class Composite extends Component {
  List<Component> children = [];

  @override
  void operation() {
    for (var child in children) {
      child.operation();
    }
  }
}

				
			

Written and reviewed by

Picture of Muhammad Naeem
Muhammad Naeem
Professional Flutter Developer
Scroll to Top