Programming in Dart: Classes

Jun 28 2022 · Dart 2.17, Flutter 3.0, DartPad

Part 2: Learn Inheritance

15. Use Abstract Classes

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 14. Challenge: Override a Method Next episode: 16. Implement an Interface

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 15. Use Abstract Classes

So far, things have been straightforward but with this episode, things are about to get a little abstract. I’m going to introduce you to abstract classes. But before we discuss abstract classes you need to understand the concept of an interface.

Typically when we think of interface, we think of a user interface. And what is the user interface? It’s a way for us to control the program.

Cars have interfaces too. It has a steering wheel to manipulate direction and pedals to go faster and slower.

And pretty much everything else has controls that we use to manipulate the object.

Not surprisingly, classes also have interfaces. It’s what we use to work with an object. And those are methods and properties. Interfaces represent the collection of methods and properties provided by a class. Now here’s where things strange - objects can have multiple different interfaces.

Take the following code.

Here we are doing two things. In the first part of the code, we are saying that the firstName is using the String interface.

In the second part, we are actually assigning a variable. Most of the times, the interface and the object is the same,

so we use the var keyword. But other times, we may want to reference a different interface. For instance, you may refer to the object interface.

This means, the firstName variable can only use the methods and properties defined in the object even though underlying object is a string. If you try to use any strings methods on the first name, you’ll get an error because you are using an object interface.

ImageGenerator generator = NetworkGenerator();
generator.fetchImage();

So why have different interfaces than objects. Often times, you’ll define the behavior that you want and you won’t care about the actual implementation.

You might define an ImagerGenerator class. One subclass may fetch that image off disk. Another may get it over the network. A third may even generate its own image based on a neural network. You don’t care how an object returns an image. You just care about the image.

Now, any of those children can be used in place of the parent which can be switched at runtime.

This brings us to abstract classes. An abstract class allows us to define an interface. But here’s the kicker - the abstract class can’t be instanced. It can only be subclassed. It can contain methods and properties that classes can inherit, but it can also define method stubs that the subclass must implement.

We’re going to define an abstract class that says hello. To do this, open up an instance of DartPad in your browser. Our abstract class will contain some text and a method for printing the text. The class doesn’t care how the text is printed. Let’s start by defining our abstract class.

abstract class HelloWorld {

}

The keyword abstract indicates that we can’t create a new instance of this class. It’s only designed to be inherited from. In fact, lets’ try to create one now.

var hello = HelloWorld();

We get an error right away. It says that the class is abstract and can’t be instanced. Okay, let’s delete that line and return back to our class. Lets add our message. It will simply read, ‘hello world’.

var message = 'Hello World!';

Next comes the message called getHelloString. This class has no intentions of implementing the method so we just provide a method signature.

String getHelloString();

By not providing an implementation for our method, we are defining it as abstract. And that’s it. That’s our abstract class. Okay, let’s make some implementations. First, let’s create an implementation that writes everything backwards. Since this is going to be a subclass, we must extend it.

class BackwardsHello extends HelloWorld {

}

Now we need to implement our getHelloString. Since this method is defined in a parent class, we must override the method.

@override

Now lets add the method.

String getHelloString() {
    return message.split('').reversed.join();
}

This method just converts the string into a list with each character being one index of the list. Then it reverses the list and joins all the characters back together as one string. Now let’s write another method with lots of shouting.

class ShoutyHello extends HelloWorld {
  @override
  String getHelloString() {
    return message.toUpperCase();
  }
}

While not real shouting, we’re still using all caps. Now in main, lets create a new BackwardsHello - except, we’re going to use the interface of the HelloWorld.

HelloWorld hello = BackwardsHello();

Dart doesn’t care that a different object is being used - it only cares that it fulfills the HelloWorld contract. Now lets say hello.

print(hello.getHelloString());

We will do the same with the shouty hello.

hello = ShoutyHello();
print(hello.getHelloString());

Run the program. And with that, we get a couple of hellos.