參、Introduction—Classes, Enums
參見: Introduction to dart–Classes
一、類別(Classes)
在Dart中也可以使用”Class”,並且建立屬性與建構子,下列為一個範例,描述了一個概念性的類別範例”Spacecraft “,說明了類別的屬性”name”, “”””,以及特定屬性的特殊處理方法”describe()”。
類別: “Spacecraft”
屬性: “name”, “launchDate”, “launchYear”
方法: “describe()”
main()
當我們要呼叫已創建的class時,就可以在mian()函式中新增符合class定義規則的物件與參數,並帶入欲執行方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| // 定義一個 Spacecraft 類別 class Spacecraft { String name; // 名稱屬性 DateTime? launchDate; // 發射日期屬性
// 讀取器,用來取得發射年份。使用 "=> launchDate?.year" 簡化寫法。 int? get launchYear => launchDate?.year;
// 建構子,使用語法糖(Syntactic sugar)簡化屬性賦值。 Spacecraft(this.name, this.launchDate) { // 初始化程式碼放在這裡。 }
// 命名建構子,將參數傳遞給預設建構子。 Spacecraft.unlaunched(String name) : this(name, null);
// 方法,用來描述太空船的資訊。 void describe() { print('太空船: $name'); // 因為 launchDate 是可為 null 的屬性,所以在這裡使用 type promotion 不適用。 var launchDate = this.launchDate; if (launchDate != null) { // 計算太空船發射後的年份。 int years = DateTime.now().difference(launchDate).inDays ~/ 365; print('發射日期: $launchYear ($years 年前)\n'); } else { print('發射日期: 尚未發射\n'); } } }
void main() { // 建立一個 Spacecraft 物件,使用建構子初始化屬性。 var voyager = Spacecraft('航行者一號', DateTime(1977, 9, 5)); voyager.describe(); // 輸出'航行者一號'太空船的資訊,包括發射年份和發射後的年數。
var unnamed = Spacecraft.unlaunched('未命名太空船'); unnamed.describe(); // 輸出'未命名太空船'的太空船資訊。 //創建兩個額外的太空船物件,作為延伸要使用Spacecraft函式的範例 var voyager2 = Spacecraft('Voyager II', DateTime(1987, 8, 20)); voyager2.describe();
var voyager3 = Spacecraft.unlaunched('Voyager III'); voyager3.describe(); }
|
class範例

二、列舉(Enums)
列舉(enum)是一種有用的資料型別,它用於定義一組具有相關值的常數。這些常數可以表示一系列可能的值,提高可讀性和維護性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| // 行星類型的列舉 enum PlanetType { terrestrial, gas, ice }
/// 行星列舉,列舉了我們太陽系中不同行星及其一些屬性。 enum Planet { mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false), // 水星 venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false), // 金星 earth(planetType: PlanetType.terrestrial, moons: 1, hasRings: false), // 地球 // ··· uranus(planetType: PlanetType.ice, moons: 27, hasRings: true), // 天王星 neptune(planetType: PlanetType.ice, moons: 14, hasRings: true); // 海王星
/// 常量生成建構子 const Planet( {required this.planetType, required this.moons, required this.hasRings});
/// 所有實例變數都是 final final PlanetType planetType; // 行星類型 final int moons; // 衛星數量 final bool hasRings; // 是否有環
/// 增強的列舉支援 getter 和其他方法 bool get isGiant => planetType == PlanetType.gas || planetType == PlanetType.ice; // 判斷是否為巨型行星 }
void main() { final yourPlanet = Planet.earth; // 創建一個行星變數,並設置為地球
if (!yourPlanet.isGiant) { print('你的行星不是 "巨型行星"。'); } }
|

肆、Introduction—繼承(Inheritance)
一、延伸(extend)
我們可以用extends的方式,將原有的Class屬性繼承,並依據需求在原有的類別上增添需要的屬性資料。例如,我們新定義一個Orbiter類別,其繼承Spacecraft,並且會新增一個”altitude”,代表軌道高度的屬性
1 2 3 4 5 6 7 8 9 10 11
| // 定義一個 Orbiter 類別,它繼承自 Spacecraft 類別 class Orbiter extends Spacecraft { double altitude; // 定義軌道高度屬性
// 建構子,使用語法糖簡化屬性賦值 // 建構子接收三個參數:name, launchDate 和 altitude // 使用 super 關鍵字呼叫父類別的建構子來初始化 name 和 launchDate 屬性 // 使用 this 關鍵字初始化 altitude 屬性 Orbiter(String name, DateTime launchDate, this.altitude) : super(name, launchDate); }
|
在使用上,Orbiter物件比原先的Spacecraft物件多了”軌道高度”的參數

二、混合(Mixins)
Mixin是一種用於在多個類別中重複使用程式碼的機制,通過with關鍵字將Mixin混合到其他類別中,使得類別可以獲得Mixin中定義的功能,提高靈活性。例如,我們定義一個”Piloted”的Mixin,具有
一個”astronauts”變數
一個”describeCrew”方法,描述太空船上的宇航員數量
1 2 3 4 5 6 7 8 9
| // 定義一個混合 (Mixin) mixin Piloted { int astronauts = 1; // 定義太空船上的宇航員數量
// 定義用來描述太空船上宇航員數量的方法 void describeCrew() { print('太空人數量: $astronauts 名'); } }
|
在使用上,我們可以透過新增”Piloted”的方式來使用額外定義原有的方法describe()與新的方法describeCrew()

三、實現(implements)
implements是一種可以將一個類別實現為多個”介面(Implicit interfaces)”,方便類別之間共享行為。例如我們定義一個”MockSpaceship”類別,他是原本”Spacecraft類別”的實現介面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| // 定義一個 MockSpaceship 類別,實現(implements) Spacecraft類別 class MockSpaceship implements Spacecraft { @override String name; @override DateTime? launchDate;
MockSpaceship(this.name, this.launchDate);
@override int? get launchYear => launchDate?.year;
@override void describe() { print('太空船: $name'); var launchDate = this.launchDate; if (launchDate != null) { int years = DateTime.now().difference(launchDate).inDays ~/ 365; print('發射日期: $launchYear ($years 年前)\n'); } else { print('發射日期: 尚未發射\n'); } } }
|
在使用上,在我們定義並實現了MockSpaceship介面後,變可以用呼叫”MockSpaceship物件”的方式達成原本呼叫”Spacecraft物件”的功能(兩個不同的類別,在”implement”的作用下,執行相同功能)

四、結合Class, Extend, Mixin, implement 綜合應用範例
我們將原有的Class與Extend, Mixin, implement中提到的”Orbiter”、”Piloted”、”MockSpaceship”進行結合,變為以下程式範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| // 定義一個 Spacecraft 類別 class Spacecraft { String name; // 名稱屬性 DateTime? launchDate; // 發射日期屬性
// 讀取器,用來取得發射年份。使用 "=> launchDate?.year" 簡化寫法。 int? get launchYear => launchDate?.year;
// 建構子,使用語法糖簡(Syntactic sugar)化屬性賦值。 Spacecraft(this.name, this.launchDate) { // 初始化程式碼放在這裡。 }
// 命名建構子,將參數傳遞給預設建構子。 Spacecraft.unlaunched(String name) : this(name, null);
// 方法,用來描述太空船的資訊。 void describe() { print('太空船: $name'); // 因為 launchDate 是可為 null 的屬性,所以在這裡使用 type promotion 不適用。 var launchDate = this.launchDate; if (launchDate != null) { // 計算太空船發射後的年份。 int years = DateTime.now().difference(launchDate).inDays ~/ 365; print('發射日期: $launchYear ($years 年前)\n'); } else { print('發射日期: 尚未發射\n'); } } }
// 定義一個混合 (Mixin) mixin Piloted { int astronauts = 1; // 定義太空船上的宇航員數量
// 定義用來描述太空船上宇航員數量的方法 void describeCrew() { print('太空人數量: $astronauts\n'); } }
// 定義一個繼承 Spacecraft 並混合 Piloted 的類別 class PilotedCraft extends Spacecraft with Piloted { // 建構子,使用 super 關鍵字呼叫父類別的建構子來初始化 name 和 launchDate 屬性 PilotedCraft(String name, DateTime launchDate) : super(name, launchDate); }
// 定義一個 MockSpaceship 類別,實現(implements) Spacecraft類別 class MockSpaceship implements Spacecraft { @override String name; @override DateTime? launchDate;
MockSpaceship(this.name, this.launchDate);
@override int? get launchYear => launchDate?.year;
@override void describe() { print('太空船: $name'); var launchDate = this.launchDate; if (launchDate != null) { int years = DateTime.now().difference(launchDate).inDays ~/ 365; print('發射日期: $launchYear ($years 年前)\n'); } else { print('發射日期: 尚未發射\n'); } } }
void main() { // 建立一個 Spacecraft 物件,使用建構子初始化屬性。 var voyager = Spacecraft('航行者一號', DateTime(1977, 9, 5)); voyager.describe(); // 輸出'航行者一號'太空船的資訊,包括發射年份和發射後的年數。
var unnamed = Spacecraft.unlaunched('未命名太空船'); unnamed.describe(); // 輸出'未命名太空船'的太空船資訊。
// 創建兩個額外的太空船物件,作為延伸要使用 Spacecraft 函式的範例 var voyager2 = Spacecraft('Voyager II', DateTime(1987, 8, 20)); voyager2.describe();
var voyager3 = Spacecraft.unlaunched('Voyager III'); voyager3.describe();
// 創建 PilotedCraft 物件,測試 PilotedCraft 類別 var pilotedCraft = PilotedCraft('Piloted I', DateTime(2005, 3, 15)); pilotedCraft.describe(); // 輸出 'Piloted I' 太空船的資訊,包括發射年份和發射後的年數。 pilotedCraft.describeCrew(); // 輸出 'Number of astronauts: 1',太空船上有1名宇航員。
// 創建 MockSpaceship 物件,測試 MockSpaceship 類別 var mockSpaceship = MockSpaceship('MockShip', DateTime(2022, 7, 1)); mockSpaceship.describe(); // 輸出 '太空船: MockShip' 和發射日期 }
|
Inheritance範例

五、抽象(abstract)
抽象(abstract)類別可以包含抽象方法,這些方法沒有實際的程式內容,只是定義方法的規範,並且可以被具體類別繼承(extend)或實現(implement)。
在下述範例中,”MyClass”是一個具體的類別,實現了 “Describable抽象類別”的describe() 方法,並提供了具體的描述內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| // 定義抽象類別 Describable abstract class Describable { void describe();//沒有方法的具體程式碼
void describeWithEmphasis() { print('\n========='); describe(); print('========='); } }
// 定義一個具體的類別,實現 Describable 抽象類別 class MyClass extends Describable { String description;
MyClass(this.description);
@override void describe() { print('Description: $description'); } }
void main() { // 創建 MyClass 物件 var myObject = MyClass('This is a sample description.');
// 呼叫 describe() 方法,輸出 myObject.describe();
// 呼叫 describeWithEmphasis() 方法,以"強調形式"輸出 myObject.describeWithEmphasis(); }
|
abstract範例
黃框為”describeWithEmphasis()”之內容
