Abstract class
You went to your local restaurant for breakfast. When you got there, you saw a lump of raw dough sitting in front of the stove. Then a boy came over and asked, “Ruti, paratha, or naan?” Whatever you say, they prepare it right on the spot and serve it to you.
Here the dough on the counter is the abstract class.
abstract class Dough{}
It exits, but it has no final form. You can not eat it raw rough dough. In programming we would say, you can not initiate it.
When a boy asked you what would you said Ruti, then the boy
tell the cooker to prepare Ruti.
Here in programming we would say, extends the class.
class Ruti extends Dough {}
Now it can be served and you can eat.
When we use the abstract keyword, it refers to an idea, and we don’t know who or how it should execute.
After eating you ordered some food to take home.
- 4 ruti
- 3 paratha
- some naans
So now the prepared others types; In programming we gonna have other classes and create objects.
class Paratha extends Dough{}
class Naan extends Dough{}
Generic
But to take home, we need to put theses into separate bags. So first each item wrap with bag; In programming we can have a generic class that can acts as a wrapper.
We know dart is a strong dataType language. So we can not simply put int into
Stringvariable;
abstract class Dough {}
class Ruti extends Dough {}
class Paratha extends Dough {}
class Naan extends Dough {}
class RutiBox<T> {
const RutiBox(this.ruti);
final T ruti;
}
void main() {
Ruti ruti = Ruti();
RutiBox box = RutiBox(ruti);
}
specific generic class
But our current generic class have one issue. We can wrap the box with a box :) loss of the business owner.
void main() {
Ruti ruti = Ruti();
RutiBox box = RutiBox(RutiBox(ruti));
}
As a good programmer we can avoid it, by specifying
class RutiBox<T extends Dough> {
const RutiBox(this.ruti);
final T ruti;
}
void main() {
Ruti ruti = Ruti();
RutiBox box = RutiBox(RutiBox(ruti)); // this will show error
RutiBox box = RutiBox(ruti); // But this is fine
}
We can have function, extensions, classes as generic. You can have more than one generic.
void printDetails<T, U>(T name, U age) {
print("I am $name and $age years old");
}
printDetails("Rahim", 25); // T becomes String, U becomes int
printDetails("Karim", "thirty"); // T becomes String, U becomes String (fully flexible!)
You can checkout dart List, Map dataType or how statefulWidget’s state class.
abstract class Input {
const Input();
void show();
}
class IntInput extends Input {
const IntInput(this.value);
final int value;
void show() => print(value.toString());
}
class StringInput extends Input {
const StringInput(this.value);
final String value;
void show() => print(value);
}
void main() {
Input v = StringInput("2");
v = IntInput(3);
v.show();
}
But what if we want to
Have a class that adapt any class we pass.
If we see our Map and List in dart, it support any dataType.
We can add, get, modify and performs others specific task.
What If we want a single Animal class, can be used for any type of data returns.
class Animal {
const Success(this.name);
final String name;
}
Now not all data will be String, we can have any type of data on Success right?
So what can we can do? Create N class just because of each Success contains
Different types of result?
Well, let’s see how Generic can be better solution here.
class Success<T> {
const Success(this.data);
final T data;
// we have methods as well
Success<T> copyWith(T data) {
return Success(data);
}
}
Now we can pass any datatype for Success.
void main() {
var result = Success<String>("Hi");
result = result.copyWith(1); // this well show compile time error
print(result.data);
// But we can have a Different object with Different dataType
var result2 = Success<int>(1);
result2 = result2.copyWith(1);
var result3 = Success<Success<int>>(result2);
print(result3.data.data);
}
Extends generic
We can force that not Every-Type will not be accepted but Only subclass of something is acceptable.
sealed class ApiState {
const ApiState();
}
class Success<T extends ApiState> {
const Success(this.data);
final T data;
Success<T> copyWith(T data) {
return Success(data);
}
}
Now we only accept any subclass of ApiState.