---
# System prepended metadata

title: Classes
tags: [OOP]

---

# [Class](https://dart.dev/language/classes)
* [Constructors](https://hackmd.io/@asdf121472/BJYsz1XG1g) 
* [Method](https://hackmd.io/@asdf121472/B14ZHRoMkx)
* [extends 繼承](https://hackmd.io/@asdf121472/SJzdoOLXye)
* [Mixin](https://hackmd.io/@asdf121472/r1y4xx_7Jl)
* [implements](https://hackmd.io/@asdf121472/B16aZfDEJe)
* [Extension methods](https://hackmd.io/@asdf121472/Hk8fumlEyx)
* [Extension types](https://hackmd.io/@asdf121472/HJdwp-Q4kg)
* [Enums](https://hackmd.io/@asdf121472/HySzeKlG0)
* [Callable objects](https://hackmd.io/@asdf121472/HJ5BN2PV1g)
* [Class modifiers](https://hackmd.io/@asdf121472/rJnfLO9Xyx)
---
參考資料:
[1](https://ithelp.ithome.com.tw/m/articles/10265921)

---
### dart是單一繼承, 配合以下方式使class可再利用:
* mixin
* extension methods
* extension type
* implements
* extends
### 類別成員
instance member:
* 物件變數
* 物件方法
* **實作的介面**

class member:
* static variable
* static method

使用點 ( . ) 來引用實例或類別的變數或方法

### 使用建構函數初始化物件
Constructor names can be either ClassName or ClassName.identifier. 
```
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
```
若要使用常數建構函式建立編譯時常數，請將const關鍵字放在建構函式名稱之前：
`var p = const ImmutablePoint(2, 2);`

```
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // They are the same instance!
```

### 取得物件的類型
```
print('The type of a is ${a.runtimeType}');

assert(a is int); // 推薦
```

### Instance variables
```
class Point {
  double? x; // 可空變數初始值是null
  double y; 
  double z = 0; // 不可空變數必須設定初始值(或用constructor來初始)
  Point(this.y);
}

```
實例變數都會產生隱式getter方法。非final or late final變數會產生隱式setter方法.

非late實例變數在物件初始化(建構函式)之前就要賦值, 此時this是不存在的.
```
double initialX = 1.5;
class Point {
  // OK, 可以用全域變數來賦值
  double? x = initialX;

  // ERROR, 此時實例還不存在
  double? y = this.x;

  // OK, 只有在使用z時才會檢查, 那時實例已經建立
  late double? z = this.x;

  // OK, `this.x` and `this.y` are parameter declarations, not expressions:
  Point(this.x, this.y);
}
```

### class本身就是接口
把一個class當接口時, 要實作其所有實例成員(實例的變數和方法, 簽名必須一樣)
```
class Person {
  String _name;
  Person(this._name);
  void intro() => print('Person name: $_name');
}

class Student implements Person {
  String _name;
  String _id;

  Student(this._name, this._id);

  void intro() => print('Student name: $_name, ID: $_id');
}

class CollegeStudent implements Student {
  String _name;
  String _id;
  int _age;

  CollegeStudent(this._name, this._id, this._age);

  void intro() => print('College student name: $_name, ID: $_id, age: $_age');
}

void main() {
  var bob = CollegeStudent("Bob Smith", '123456', 19);
  bob.intro();
}
```
```
// class B實作接口class A
// 則B是A的subclass
class A {
  int a;
  A(int b) : a = b;
}

class B implements A {
  int a;
  int b;
  B(this.a, this.b);
}

void main() {
  var aa = A(23);
  print(aa.a);

  var bb = B(12, 45);
  print(bb.b);

  assert(bb is A);
  assert (bb is B);
  // assert(aa is B);
}

```
可以實作多個接口
`class Point implements Comparable, Location {...}`
### 類別(靜態)變數和方法
使用`static`宣告變數或方法為類別所有, 用類別調用, 不是用實例調用.
靜態方法可以讀取靜態變數
```
class Circle {
  static const pi = 3.14159;

  int originX, originY;
  Circle(this.originX, this.originY);

  // 不能讀取originX, originY, 但可直接讀取類別變數pi
  static num area(num radius) => pi * radius * radius;
}

void main() {
  num area = Circle.area(12);
  print(area); // 452.38895999999994
}
```














