Introduction to the
Dart is an object-oriented language that supports mixin-based inheritance. All objects are instances of a class, and all classes except Null inherit from the Object class. This article uses a Car example to explain extends, implements, with, and extension functions to see the characteristics and differences between them.
An abstract class
In object-oriented concepts, all objects are represented by classes, but conversely, not all classes are represented by objects. If a class does not contain enough information to represent a concrete object, such a class is an abstract class. In addition to not being able to instantiate objects, the rest of the functionality of an abstract class still exists. Member variables, member methods, and constructors are accessed just like normal classes. In Dart, identifying a class with the keyword abstract makes it abstract. Abstract classes are often used to declare interface methods and sometimes have concrete method implementations.
///Automobile Abstract Class
abstract class Car {
int wheel = 4; // Default four rounds
int horsepower; / / HP
///Set the horsepower
void setHorsepower(int power) {
horsepower = power;
}
///driving
void drive() {
print('You can take the car and run');
}
///Output horsepower (abstract function)
void showHorsepower();
///Gate (Abstract function)
void door();
}
Copy the code
The above code defines an abstract car class with two variables: wheel and setup. And four methods. ShowHorsepower and door are abstract functions without any implementation. Drive and setHorsepower are common member functions.
Abstract functions have several properties:
- Abstract cannot be instantiated directly.
- A function that does not have any function implementation is an abstract function and does not need the abstract modifier.
- An abstract class may not have abstract functions, but a class with abstract functions must be an abstract class.
- Subclasses need to override all abstract functions, but they are not required to override ordinary member functions of their parent class.
extends
Like Java, Dart is single-inherited. A class can have only one direct parent, which defaults to Object if not specified directly.
Example and method rewrite
class SportCar extends Car {
final int defaultPower = 200;
@override
void door() {
print('I'm a two-door two-seater with a big rear super$wheelA wheel ');
}
@override
void showHorsepower() {
if(horsepower == null) {
super.setHorsepower(defaultPower);
}
print('I'm$horsepowerHorsepower '); }}Copy the code
The code above creates a sports car and rewrites the door and showHorsepower functions. The showHorsepower function determines if the setup is empty or not. If it is empty, the showHorsepower function of the parent class will set the horsepower. In door, we can see that subclasses can call the parent’s private variables directly. Run the following code to create a SportCar and execute the related methods:
var mx5 = SportCar();
mx5.showHorsepower();
mx5.door();
mx5.drive();
Copy the code
The output is:
I have 200 horsepower. I'm a two-door, two-seater with over four wheels. You can take it and run itCopy the code
As you can see, we must override the abstract functions of the parent class; we are not forced to override the member functions. But we can still override these member functions. For example, we’ll add a turbo to our sports car to boost its horsepower. We rewrite the setHorsepower function:
class SportCar extends Car {
final int defaultPower = 200;
@override
void door() {
print('I'm a two-door two-seater with a big rear super$wheelA wheel ');
}
@override
void showHorsepower() {
if(horsepower == null) {
setHorsepower(defaultPower);
}
print('I'm$horsepowerHorsepower ');
}
@override
void setHorsepower(int power) {
power =turbo(power);
super.setHorsepower(power);
}
int turbo(int power){
///Turbo increases horsepower by 20%
return power~/5+ power; }}Copy the code
The adjusted code is as follows:
I got 240 horsepower and I got a two-door two-seater with four wheels and you can drive itCopy the code
Subclasses can also override variables of their parent class:
@override
int wheel = 8;
@override
void door() {
print('I'm a two-door two-seater with a big rear super${wheel}A wheel ');
print('I'm a two-door two-seater with a big rear superThe ${super.wheel}A wheel ');
}
Copy the code
The following output is displayed:
I'm a two-door two-seater with eight wheels and a two-door two-seater with four wheelsCopy the code
Finally, add the complete code:
class SportCar extends Car {
final int defaultPower = 200;
@override
int wheel = 8;
@override
void door() {
print('I'm a two-door two-seater with a big rear super${wheel}A wheel ');
print('I'm a two-door two-seater with a big rear superThe ${super.wheel}A wheel ');
}
@override
void showHorsepower() {
if (horsepower == null) {
setHorsepower(defaultPower);
}
print('I'm$horsepowerHorsepower ');
}
@override
void setHorsepower(int power) {
power = turbo(power);
super.setHorsepower(power);
}
int turbo(int power) {
///Turbo increases horsepower by 20%
return power ~/ 5+ power; }}Copy the code
conclusion
- Abstract cannot be instantiated directly.
- A function that does not have any function implementation is an abstract function and does not need the abstract modifier.
- An abstract class may not have abstract functions, but a class with abstract functions must be an abstract class.
- Subclasses need to override all abstract functions, but they are not required to override ordinary member functions of their parent class.
- Subclasses can access the parent class’s member variables and functions (private or private). If the subclass overwrites the parent class’s functions or member variables, the subclass passes
super.
Add a function or variable name to access a function or member variable of the parent class. Functions and variables in subclasses and superclasses are independent of each other.
Interface and implements
Dart does not have the interfaces keyword. When interfaces are needed, you can declare classes instead. Because in Dart, you use an implicit interface: each class implicitly defines and implements an interface that contains all the instance members of that class and other interfaces that that class implements. If you want to create A class A API that supports calling class B without inheriting from class B, you can implement A class B interface. For example, we want to build a Tank that has the horsepower and driving power of Car, but it is not Car:
class Tank implements Car{
@override
int horsepower;
@override
int wheel = 5;
@override
void door() {
print('I have$wheelFive pairs of roadwheels');
}
@override
void drive() {
print('59 went down the hill ');
}
@override
void setHorsepower(int power) {
horsepower = power;
}
@override
void showHorsepower() {
print('I diesel engine$horsepowerHorsepower '); }}Copy the code
The running results are as follows:
I have 1600 horsepower diesel engines and I have 5 5 pairs of roadwheels and 59 down the hillCopy the code
Notice in the code above that when implementing a class as an implicit interface, you need to override all of its methods and member variables.
Dart also supports multiple inheritance. If you need to implement multiple interface classes, you can use commas to separate each interface class:
class Tank implements Car, Cannon, Gun {
}
Copy the code
The complete code is as follows:
class Cannon {
void fire() {
print('fire! '); }}abstract class Gun {
void gun();
}
class Tank implements Car.Cannon.Gun {
@override
int horsepower;
@override
int wheel = 5;
@override
void door() {
print('I have$wheelFive pairs of roadwheels');
}
@override
void drive() {
print('59 went down the hill ');
}
@override
void setHorsepower(int power) {
horsepower = power;
}
@override
void showHorsepower() {
print('I diesel engine$horsepowerHorsepower ');
}
@override
void fire() {
print('fire! ');
}
@override
void gun() {
print('This is machine gun!! OK, hahah ' '); }}Copy the code
Mixins and with
Dart adds a Mixin mechanism, or blending. Mixins are a way to implement multiple inheritance by adding features to existing classes to achieve a similar effect. For example, we need maintenance and refueling for oil vehicles and charging and maintenance for electric cars:
class Oil {
void refuel() {
print('Went to the gas station to get gas.');
}
void maintain() {
print('I need to change the oil filter coolant and check the tire battery.'); }}mixin Electricity {
void charge() {
print('Went to the charging pile.');
}
void maintain() {
print('I need to check the tire batteries.'); }}Copy the code
A Mixin can be a plain class, or it can be modified by replacing a class with a Mixin. The difference is that classes decorated with mixins cannot create instances directly.
Create a tanker and a tram separately:
class SedanOil extends Car with Oil {
@override
void door() {
print('I'm a four-door, two-seater super.');
}
@override
void showHorsepower() {
print('I'm$horsepowerHorsepower '); }}class SedanElectricity extends Car with Electricity {
@override
void door() {
print('I have five doors and five POTS.');
}
@override
void showHorsepower() {
print('I put on the horsepower$horsepowerHorse ');
}
}
main(){
print('-------- oil tanker: ');
varsedanOil = SedanOil().. horsepower =200;
sedanOil.showHorsepower();
sedanOil.maintain();
sedanOil.refuel();
print('-------- Tram: ');
varsedanElectricity = SedanElectricity().. horsepower =300;
sedanElectricity.showHorsepower();
sedanElectricity.maintain();
sedanElectricity.charge();
}
Copy the code
The following output is displayed:
-------- oil car: I need to change the oil three filter coolant, check the tire battery went to the gas station to fill up -------- trolley car: I have 300 horsepower on the wheel I need to check the tire battery to charge the charging pileCopy the code
The code above: use the with keyword to implement blending, separating multiple blended classes with commas. Next, we add fuel tank to the oil vehicle related operations:
class SedanOil extends Car with Oil.OilTank{
@override
void door() {
print('I'm a four-door, two-seater super.');
}
@override
void showHorsepower() {
print('I'm$horsepowerHorsepower ');
}
@override
void remove() {
volume -=volumeSpare;
print('to remove the$volumeSpareLitre drop tank ');
volumeSpare = 0; }}abstract class OilTank{
int volume = 68;
int volumeSpare = 0;
///Add a spare fuel tank
void spare(int b){
volumeSpare = b;
volume+=b;
print('increased$volumeSpareLitre drop tank ');
}
///Remove reserve tank
void remove();
}
Copy the code
Add an abstract OilTank class that allows us to add a drop tank. But we must implement the abstract method remove of the abstract class.
Similarly, for electric cars, we can mix in the operations related to batteries:
abstract class ElectricityCar extends Car with Electricity implements Battery {
@override
void replenishCoolant() {
print('Add coolant'); }}mixin BladeBattery on ElectricityCar{
void safe(){
print('Blade battery I'm safer'); }}class SedanElectricity extends ElectricityCar with BladeBattery{
@override
void door() {
print('I have five doors and five POTS.');
}
@override
void showHorsepower() {
print('I put on the horsepower$horsepowerHorse ');
}
@override
int electricity;
}
Copy the code
We created a SedanElectricity that descends from the tram parent ElectricityCar and then mixes it with a BladeBattery, BladeBattery. Note that BladeBattery is followed by the keyword on, indicating BladeBattery’s mixin range. This keyword means that the class that wants to blend into BladeBattery must be a subclass of subsequent ElectricityCar. Blade batteries can only be used by trams.
print('-------- Tram: ');
varsedanElectricity = SedanElectricity().. horsepower =300;
sedanElectricity.showHorsepower();
sedanElectricity.maintain();
sedanElectricity.charge();
sedanElectricity.replenishCoolant();
sedanElectricity.safe();
Copy the code
Running the code above produces the following output:
-------- tram: I have 300 horsepower on wheels and I need to check the tires and batteries to charge the piles and add coolant blade batteries and I'm much saferCopy the code
At this point, if we need a plug-in hybrid:
class SedanDmi extends Car with Oil.Electricity {
bool hasOil = false;
@override
void door() {
print('I'm a four-door, five-seater.');
}
@override
void showHorsepower() {
print('I have$horsepowerHorsepower ');
}
@override
void maintain() {
super.maintain();
}
@override
void charge() {
if (hasOil) {
print('The engine charges the battery');
hasOil = false;
} else {
print('Went to the charging pile to recharge or fill up.');
hasOil = true; }}}Copy the code
Run the following code in a car with oil and electricity mixed in:
var dmi = SedanDmi().. horsepower = 300; dmi.showHorsepower(); dmi.maintain(); dmi.charge();Copy the code
The output is:
I have 300 horsepower and I need to check the tires and the batteries to recharge the charging pile or to fill up the tankCopy the code
Note: Both Oil and Electricity require maintenance. They have the same name maintain(). As you can see, when mixing multiple classes, if there is a function with the same name, the class at the end of the Mixin overwrites all previous methods with the same name.
- It can be a normal class that cannot be instantiated with mixins;
- If it is an abstract class, it needs to implement all the abstract functions after mixing.
- You can use the keyword on to specify which classes can use the Mixin class. (Of course, you can also implement this Mixin class using ElectricityCar in a superclass, but this is a departure from the junior middle of design, which is not explained here.)
- When mixing multiple classes, if there is a function with the same name, the class at the end of the Mixin overwrites all previous methods with the same name.
- Mixins are a way to reuse class code across multiple class hierarchies.
conclusion
Personal understanding:
- 1. Extends inheritance specifies what a class is;
- 2. Implements an interface that indicates what a class does.
- 例 句 : Add some functionality to the class, the most important of which is to reuse code. The significant difference from implements is that you don’t have to rewrite all the methods (except abstract methods) that implement a mixin class
The code examples