Abstract classes in Dart

ref –

  • https://medium.com/@manoelsrs/dart-extends-vs-implements-vs-with-b070f9637b36
  • https://en.wikipedia.org/wiki/Dependency_inversion_principle
  • https://stackoverflow.com/questions/3108182/using-parameter-that-implements-multiple-interfaces-pre-generics
  • https://flutterbyexample.com/lesson/abstract-classes-and-interfaces

Dart has no interface keyword. Instead, all classes implicitly define an interface. Therefore, you can implement any class.

You can create an abstract class to be extended by children abstract classes, (or implemented) by a concrete class. Abstract classes can contain abstract methods (with empty bodies).

Let’s first take a look at base classes and inheritance. We have a base class Vehicle with a constructor and some properties.

We then create a Car class and extends from this Vehicle.

Furthermore, we create a Hatch, and then extends from Car.

Finally, Hatch, being on the grand child inherits properties from both parent and grandparent.

Inheritance allows us to create new classes that reuse, extend and/or modify pre-existing classes behavior. The pre-existing class is called superclass and the new class we’re creating is called derived class.

In Dart, we can inherit only one superclass, but inheritance is transitive.

If the class Hatch is derived from the class Car and this class is derived from class Vehicle, then Hatch will be derived from Vehicle.

Use extends to create derived class, and super when you want to refer to the superclass. When class Car extends Vehicle, all properties, variables, functions implemented in class Vehicle will be available in class Car.

Suppose you want to create your own Car class, without inhering all the properties, variables and functions of the Vehicle class, but you want to inherit only the Vehicle type.

To do this, the Car class must implement the Vehicle interface by using abstract classes.

Abstract classes cannot be Instantiated!

Follows the concept of Dependency Inversion Principle

Given an abstract class Shape, we cannot instantiate it. We can only extend from it.

We create the shapes that must implement this abstraction:

Circle

Square

main.dart

We can implement abstract classes from more than one interface

…however, we can only extend from one parent class

Let’s take a look at the basics
We have abstract class A with a()

and abstract class B with b()

When we have a class AB that implements both A and B, it means we must implement both a() and b()

If we do not, it will complain. Because essentially we conform to the interfaces. It’s a pact with our abstraction that we will be implementing them.

Even if the abstract interface method is implemented, we must implement it.

Concrete classes can be instantiated. We extend from concrete classes.
Abstract classes CANNOT be instantiated. We implement abstract classes.

Passing instances that implements an abstract class

When we’re dealing with abstractions, we can specify that the object that is being passed in must implement a certain abstract class.

In our example, we have abstract class Person. In our parameter for function gate, we say that the parameter named person is an object that must implement Person.

So we create an instance of class Kid, which implements Person. We then pass kid into the parameter and it will be valid to be used. This encourages dependency inversion principle where modules are loosely coupled.

But what if we want it to conform to multiple interfaces?

ref – https://stackoverflow.com/questions/3108182/using-parameter-that-implements-multiple-interfaces-pre-generics

There are basically three ways to go about doing this:

1) Use function parameters to check against each abstraction, and pass in the same object.

So we have our interfaces

We have a Person class that implements both abstract classes

We have a function that takes in both interfaces. Just with different names. Each param checks on one abstraction, and since we want to check on two, then we just use two params for it.
It does this during compile time.

Then if both passes, then just use your object to access whatever abstract method you need.

In main, we just pass in the same object. The params of connectIt will check each abstraction for us.

2) Create another abstract class that implements both

3) Simply use type Person instead of an abstraction in connectIt’s parameter definition.

Intricacies

As an abstract child class, if we were to simply use the parent abstract class’s property, it will display the value there. So the parent abstract class will need to initialize it from property declaration, or constructor initialization.

As an abstract child class, if we over-ride property from parent, and try to use it, we’ll get an error. This is because when we use over-ride, we’re declaring the property on the child class, instead of using the parent class’s property.

As an abstract child class, if we did over-ride property from parent, we need to make sure we initialize it either from declaration:

or constructor: