Dart: Abstract class & method

Dart: Abstract class & method

To define a class that doesn’t require a full, concrete implementation of its entire interface, use the abstract modifier.

Abstract classes cannot be constructed from any library, whether its own or an outside library. Abstract classes often have abstract methods.

We can not create object of abstract class, for access Abstract class and method we have to extend abstract to another class and create object to other class , then we can access all the element of Abstract class.


// Objectives
// 1. Abstract Method
// 2. Abstract Class

void main() {

//    var shape = Shape();        // Error. Cannot instantiate Abstract Class

    var circle = Circle();
    circle..draw()..circleArea();
}

abstract class Shape {

    // Define your Instance variable if needed
    int x =5;


    void draw();        // Abstract Method

    void circleArea() {
      print("Circle Area is ${3.14*x*x}");
    }
}


class Circle extends Shape {

    void draw() {
        print("Calacute Circle Area.....");
    }
}

Dart Abstract Class: Treating Concrete Classes as Abstract

Dart, known for its flexibility and expressive syntax, offers developers various ways to design and structure their code. One intriguing approach that might not adhere strictly to conventional wisdom is treating concrete classes as abstract. In this exploration, we'll delve into the concept of Dart abstract classes, understand their conventional use, and then break some norms by considering how concrete classes can be treated with an abstract mindset.

Understanding Dart Abstract Classes

In Dart, abstract classes play a pivotal role in facilitating polymorphism and code organization. An abstract class serves as a blueprint for other classes, providing a common interface and potentially containing abstract methods—methods without a default implementation. Concrete subclasses must implement these abstract methods, ensuring adherence to the defined structure.

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

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

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

In this standard usage, the Shape abstract class defines an abstract method draw, which concrete subclasses like Circle and Square must implement.

Breaking Conventions: Treating Concrete Classes as Abstract

Now, let's venture into unconventional territory—treating concrete classes as abstract. While Dart doesn't explicitly support the abstract keyword for concrete classes, we can adopt a mindset where a base concrete class provides default implementations that can be either overridden or extended by its subclasses.

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

  void eat() {
    print('Eating...');
  }
}

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

  void fetch() {
    print('Fetching the ball');
  }
}

Here, Animal is a concrete class with default implementations for makeSound and eat. The Dog class, as a subclass of Animal, inherits these behaviors and can choose to override or extend them.

Use Cases for Treating Concrete Classes as Abstract

1. Providing Sensible Defaults

Treating concrete classes as abstract can be particularly useful when you want to offer sensible default implementations for certain methods while still allowing subclasses to customize or extend the behavior.

class BaseController {
  void initialize() {
    print('BaseController initialized');
    // Additional initialization logic
  }

  void performAction() {
    print('Performing default action');
    // Default action logic
  }
}

class CustomController extends BaseController {
  @override
  void initialize() {
    super.initialize();
    print('CustomController initialized');
    // Additional initialization logic specific to CustomController
  }

  @override
  void performAction() {
    super.performAction();
    print('Performing custom action');
    // Custom action logic
  }
}

In this scenario, BaseController provides default implementations for initialize and performAction. Subclasses like CustomController can override these methods based on their specific requirements.

2. Gradual Refactoring

Treating concrete classes as abstract can be part of a gradual refactoring process. If you have existing concrete classes that you want to make more extensible, introducing a base class with default implementations allows you to migrate subclasses gradually.

Considerations and Best Practices

While treating concrete classes as abstract offers flexibility, it's essential to consider some best practices:

  1. Documentation: Clearly document the intention and design decisions behind treating concrete classes as abstract. This unconventional approach may deviate from standard patterns, so providing guidance for developers is crucial.

  2. Code Reviews: Incorporate discussions about the rationale behind treating concrete classes as abstract in your code reviews. This helps maintain code readability and a shared understanding within the development team.

  3. Consistency: If you choose to adopt this approach, strive for consistency in its application across the codebase. Consistent use helps developers understand and predict class behaviors.

  4. Testing: Thoroughly test subclasses to ensure that they behave as expected. While default implementations in the base class aim to provide sensible behavior, subclasses might introduce additional complexities.

Did you find this article valuable?

Support Vinit Mepani (Flutter Developer) by becoming a sponsor. Any amount is appreciated!