[TOC]
Dart是一種“純粹的”面向對象語言,因為所有對象都是類的實例。但Dart并不要求在類中定義所有代碼 - 您可以在過程或函數語言中定義頂級變量,常量和函數。
## 避免在簡單函數可以勝任時定義一個成員的抽象類。
與Java不同,Dart具有一流的功能,閉包和使用它們的輕松語法。如果您只需要回調,只需使用一個函數即可。如果您正在定義一個類,并且它只有一個具有無意義名稱的抽象成員,call或者invoke,您很可能只需要一個函數。
~~~
typedef Predicate<E> = bool Function(E element);
~~~
以下是反面例子:
~~~
abstract class Predicate<E> {
bool test(E element);
}
~~~
## 避免定義僅包含靜態成員的類。
在Java和C#中,每個定義都必須在一個類中,所以通常看到“類”只存在于靜態成員的位置。其他類用作命名空間 - 一種為一堆成員提供共享前綴以使它們彼此關聯或避免名稱沖突的方法。
Dart具有頂級函數,變量和常量,因此您不需要一個類來定義某些東西。如果您想要的是命名空間,那么庫更適合。庫支持導入前綴和顯示/隱藏(show/hide)組合器。這些功能強大的工具可讓代碼的使用者以最適合他們的方式處理名稱沖突。
如果函數或變量在邏輯上與類無關,請將其置于頂層。如果您擔心名稱沖突,請為其指定更精確的名稱,或將其移動到可以使用前綴導入的單獨庫中。
~~~
DateTime mostRecent(List<DateTime> dates) {
return dates.reduce((a, b) => a.isAfter(b) ? a : b);
}
const _favoriteMammal = 'weasel';
~~~
以下是反面例子:
~~~
class DateUtils {
static DateTime mostRecent(List<DateTime> dates) {
return dates.reduce((a, b) => a.isAfter(b) ? a : b);
}
}
class _Favorites {
static const mammal = 'weasel';
}
~~~
在慣用的Dart中,類定義了各種對象。從未實例化的類型是代碼特征。
但是,這不是一個嚴格的規定。對于常量和類似枚舉的類型,將它們組合在一個類中可能是很自然的。
~~~
class Color {
static const red = '#f00';
static const green = '#0f0';
static const blue = '#00f';
static const black = '#000';
static const white = '#fff';
}
~~~
## 避免擴展了一個不打算進行子類擴展的類。
如果構造函數從生成構造函數更改為工廠構造函數,則調用該構造函數的任何子類構造函數都將中斷。此外,如果一個類更改了它調用的自己的方法this,那么可能會破壞覆蓋這些方法的子類,并期望在某些點調用它們。
這兩個都意味著一個類需要考慮是否要允許子類化。這可以在doc注釋中提現,或者通過給類明顯的名稱來表達IterableBase。如果類的作者不這樣做,它的最好假設你應該不擴展類。否則,稍后更改它可能會破壞您的代碼。
## 如果你的類支持擴展請提供文檔注釋
這是上述規則的必然結果。如果要允許類的子類,請說明。使用類名稱后綴Base,或在類的doc注釋中提及它。
## 避免實現一個不打算成為接口的類。
隱式接口是Dart中的一個強大工具,可以避免在從該合同的實現簽名中輕易推斷出類的合同時重復它。
但實現類的接口是與該類非常緊密的耦合。它實際上意味著對您正在實現的接口的類的任何更改都將破壞您的實現。例如,向類中添加新成員通常是安全,不間斷的更改。但是如果你正在實現該類的接口,那么現在你的類有一個靜態錯誤,因為它缺少該新方法的實現。
庫維護者需要能夠在不破壞用戶的情況下發展現有類。如果你把每個類都視為暴露了一個用戶可以自由實現的接口,那么改變這些類就變得非常困難了。反過來,這種困難意味著您所依賴的庫增長速度較慢,能夠適應新的需求。
為了給你的類的作者提供更多的余地,避免實現隱式接口,除了明確要實現的類。否則,您可能會引入作者不想要的耦合,并且可能會在沒有意識到的情況下破壞您的代碼。
## 如果你的類支持作為接口使用請提供文檔注釋。
如果您的類可以用作接口,請在類的doc注釋中提及。
## 避免在并不支持mixing的類中使用mixin
如果將一個構造函數添加到以前沒有定義任何類的類中,那么會破壞混合它的任何其他類。這是類中看似無害的變化,并且對mixin的限制并不廣為人知。作者可能會添加一個構造函數而不會意識到它會破壞你的類混合它。
與子類化一樣,這意味著類需要考慮是否允許將其用作mixin。如果班級沒有文檔注釋或明顯的名稱IterableMixin,你應該假設你不能在類中使用mix。
## 如果您的類支持用作mixin,請提供文檔注釋。
在類的文檔注釋中提及該類是否可以或必須用作mixin。如果您的類只是作為mixin使用,那么請考慮添加 Mixin到類名的末尾。