Dart是一個物件導向語言,同時支持混入(mixin)的繼承機制。每個物件都是一個類別的實體,所有的類別都繼承於object。基於Mixin的繼承意味著每個類別(Object除外)都只有一個父類別,一個類別可以在其他多個類別繼承中重複使用。使用new關鍵字和建構式來建立新的物件。建構式的名字可以為ClassName或者ClassName.identifier。
宣告一個類別,使用關鍵字class開頭,後跟類別名稱; 接著使用一對大括號包圍程式碼。如下所示
class class_name {
<fields>
<getters/setters>
<constructors>
<functions>
}
類別可包括以下內容:
欄位(fields) - 欄位是類別中宣告的變數。
getters和setters - 允許程式初始化和檢索類別欄位的值,預設的getter/setter與每個類別相關聯。但是可以通過顯式定義setter/getter來覆蓋預設值。
建構式(constructors) - 為類別的物件分配記憶體。
函式(functions) - 函式表示物件可以採取的操作,也稱為方法。
以上稱為類別的資料成員。
做一個範例如下,宣告一個類別Car。該類別有一個brand的欄位;一個簡單的方法 disp(),列印出廠牌這個欄位的值。
class Car {
// field
String brand = 'Tesla';
// function
void disp() {
print(brand);
}
}
語法
目前建立類別的實體,不用加上new, 這樣看起來更簡潔。直接讓變數等於建構式即可。
var object_name = class_name([ arguments ]);
把上面的Car類別,建立出實體
void main() {
var car1 = Car(); //建立 Car 的實體 物件:car1
print(car1.brand); //Tesla
}
class Car {
// field
String brand = 'Tesla';
// function
void disp() {
print(brand);
}
}
建構式是類別的特殊函式,負責初始化類別。建構式是一個與類別名稱相同的函式,它是一個函式,因此可以傳入參數。但是與函式不同的地方,在於建構式不能具有返回型別。如果未宣告建構式,則會預設無參數的建構式。
語法
class_name(parameter_list) {
//constructor body
}
用上面的Car類別來修改,加上含有一個參數的建構式。這裡有用到 this 關鍵字, 代表物件本身。
void main() {
var car1 = Car('Benz');
var car2 = Car('BMW');
print(car1.brand);
car2.disp();
}
class Car {
// field
String brand = 'Tesla';
//constructors
Car(String b) {
this.brand = b;
}
// function
void disp() {
print('The brand of the car is $brand');
}
}
由於Dart不支援同一名稱但是不同參數的多形建構式,以 Car 類別為例子,只能有一個名稱叫做Car的建構式,
若是需要建立其他的建構式,需要命名為其他名稱來建立,例如 Car.fromBC(brand, color)來建立。
void main() {
var car1 = Car('Benz');
var car2 = Car.fromBC('BMW', 'black');
car1.color = 'red';
car1.disp();
car2.disp();
}
class Car {
// field
String brand;
String color;
//constructors
Car(String brand) {
this.brand = brand;
}
//這裡採用命名建構式,並使用簡寫方式建立
Car.fromBC(this.brand, this.color);
// function
void disp() {
print('The brand of the car is $brand and color is $color.');
}
}
Getters(存取器)和Setter(更改器)允許程式分別初始化和檢索類欄位的值。
Getters:使用get關鍵字定義。沒有參數,會回傳值。
Setter:使用set關鍵字定義。只有一個參數,且不回傳值。
語法
//getter
return_type get identifier
{
}
//setter
set identifier
{
}
void main() {
var car1 = Car('Benz', 'red');
var car2 = Car('BMW', 'blue');
car1.disp();
car2.disp();
car1.setColor = 'black';
print('The Color of this car reset to ${car1.getColor}');
}
class Car {
// field
String brand;
String color;
//constructors
Car(this.brand, this.color);
//Setter
set setColor(String c) {
color = c;
}
set setBrand(String b) {
brand = b;
}
//getter
String get getColor => color;
String get getBrand => brand;
// function
void disp() {
print('The brand of the car is $brand and color is $color.');
}
}
利用static 可以實現,在相同的類別之間的物件,可以共享欄位值與函式。要注意的是,若修改了類別上的static 的值,則所有該類別產生的物件都會受到影響,使用時需特別小心。
void main() {
var person1 = Person('Dragon', 'Chen');
var person2 = Person('Jefferson', 'Lin');
print(person1.showFullName);
print(person2.showFullName);
Person.sayHi(person1);
Person.sayHi(person2);
Person.label = 'Your name is';
print(person1.showFullName);
print(person2.showFullName);
Person.sayHi(person1);
Person.sayHi(person2);
}
class Person {
// field
String firstName;
String lastName;
static String label = "Person's name is ";
//constructors
Person(this.firstName, this.lastName);
//Setter
set fullName(String f) {
var temp = f.split(' ') ;
firstName = temp.first;
lastName = temp.last;
}
set setFirstName(String f) {
firstName = f;
}
set setLastName(String l){
lastName = l;
}
//getter
String get getFirstName => firstName;
String get getLastName => lastName;
String get showFullName => '$label $firstName $lastName';
// static function
static void sayHi(Person p) {
print('Hi $label ${p.firstName} ${p.lastName}');
}
}
extends: 關鍵字來繼承類別。要注意的是,除了建構式之外,全部的成員都會繼承。不支援多重繼承。
super: 可呼叫父層變數,屬性或函式等等。。
@override: 重載(reload),也就是重新定義父層的函式,但是參數的數量和型別必須匹配。
語法
class child_class_name extends parent_class_name
void main() {
var circle1 = Circle();
circle1.area();
circle1.color = 'red';
print('my color is ${circle1.showColor}');
}
class Shape {
String color;
void area() {
print("show area");
}
String get showColor => color;
}
class Circle extends Shape {}
void main() {
var person1 = Person('Dragon','Chen');
var person2 = Doctor('Jefferson','Lin','Badboy');
print(person1);
print(person2);
}
class Person {
String firstName;
String lastName;
String get fullName => '$firstName $lastName';
Person(this.firstName, this.lastName);
}
class Doctor extends Person{
String nickName;
Doctor(String f, String l, this.nickName) :super(f,l);
@override String toString() => 'Hi Doctor $fullName, also known as $nickName';
}
使用abstract關鍵字定義一個抽象類別,一個不能被實體化的類別,抽象類別通常用來定義介面(interface)。
void main() {
var doctor1 = Doctor('Dragon', 'Chen', 'DC');
print(doctor1.fullName);
}
abstract class Person {
String firstName;
String lastName;
String get fullName;
Person(this.firstName, this.lastName);
}
class Doctor extends Person {
String nickName;
Doctor(String f, String l, this.nickName) : super(f, l);
@override
String get fullName =>
'Hi Doctor $firstName $lastName, also known as $nickName';
}
例子中可以看出,實體化Doctor類別,而不是實體化Person。而Person類別中的 fullName為抽象的getter且未實作,因此在子類別 Doctor中需實作 fullName。
Dart語言中,並未定義interface這個關鍵字,而是類別本身就是介面,也就是說類別除了可以被繼承也可以被實作(implements)。
void main() {
var doctor1 = Doctor('Dragon', 'Chen', 'DC');
print(doctor1.fullName);
}
abstract class Person {
String firstName;
String lastName;
String get fullName;
Person(this.firstName, this.lastName);
}
class Doctor implements Person {
String nickName;
@override String firstName;
@override String lastName;
Doctor(this.firstName, this.lastName, this.nickName);
@override
String get fullName =>
'Hi Doctor $firstName $lastName, also known as $nickName';
}
上面的例子顯示,實作介面,就像是Person類別先設定好該有的成員,然後Doctor類別將內容實作出來。
實現多個介面,介面名稱之間用逗號分隔。語法如下:
class identifier implements interface-1,interface_2,interface_4…….
void main() {
var c = Calculator();
print('The gross total : ${c.retTot()}');
print('Discount :${c.retDis()}');
}
class CalculateTotal {
// ignore: missing_return
int retTot() {}
}
class CalculateDiscount {
// ignore: missing_return
int retDis() {}
}
class Calculator implements CalculateTotal,CalculateDiscount {
@override
int retTot() {
return 1000;
}
@override
int retDis() {
return 50;
}
}
因為只能單一繼承,若是想要增加別的類別的函式功能,類似多重繼承,就是使用混入(mixin)。
可以使用關鍵字mixin來取代class來宣告一個混入的類別,該類別就是一個讓別的類別混入的類別。
混入類別無法被繼承,且沒有建構式。若要限制使用混入的類別,可用on關鍵字指定。
使用 with 來添加混入的類別。
mixin ProgrammerSkills on Developer{
void coding(){
print('writing code');
}
}
class Developer extends Person with ProgrammerSkills, ManagerSkills{
...
}```