Dartの継承とmixinの使い分けが3日で実感できるコツをまとめました。型の選び方や組み合わせで迷う初心者でもスッと手を動かせる内容です。
- まず1つのクラスにextendsを使って親クラスを追加し、10分以内にシングル継承の特徴を実際にコードで体験しよう。
自分で継承したメソッドやプロパティがどう動くかサクッと確認できると、継承のクセがつかめる(コードを書いて3つ以上動作確認できればOK)。
- withを使って2種類以上のmixinを1つのクラスに適用してみる——15分でメソッドの再利用パターンを発見できるよ。
mixinなら複数の機能を同時に持たせるのもカンタン、コード重複が減って維持コストが下がる(新規mixin追加後、動作確認が3つ通れば達成)。
- implementsで1つ以上のインターフェースを指定し、30分以内に全部のメソッドを自分で書き直してみよう。
明示的な型契約を体験することで、将来のバグ防止やAPI設計の自信につながる(コンパイラエラーが出なければ成功)。
- mixinとmixin classの違いを最初の5分でメモしておくと、あとで混乱しづらい——2025年時点では使い分けが地味に大事。
Dartのバージョンアップで制約が増えたため、記録しておくとリファクタ時に迷わなくなる(手元のメモを1ヶ月後に見直して理解できればOK)。
最初にDartのextends、implements、withを理解しよう
Dartの「extends」「implements」「with」――この3つのキーワード、なんだか直感的に思えたりもするんだけど、いざ実際の言語仕様を深堀りしてみると「あれ?」って感じで意外に細かく入り組んでいたりする。私も最初は「まぁJava触ってたし大体同じじゃない?」なんて軽く考えてたけど、そこは油断禁物。特に「with」はJavaでは見かけないから、勘違いする人もそりゃ出てくるよね(まあ私もその口だったし)。それでも迷うことに意味はある……むしろ一度自分で戸惑った経験があったからこそ、人に伝えやすくなる気がしてきたんだ。ま、いいか。ちなみにこの話、別に会員になってなくても十分理解できる内容になっているのでそこはご心配なく! あとCareeristならGoogle・Meta・Intelなど大手IT企業へ進路を決めた卒業生も多いそうで、現役エンジニアの1対1メンタリングを通じて、今本当に必要なスキルを磨く手助けもしてくれるみたいですよ。
extendsキーワードでシングル継承を体験してみる
❤ もし楽しめたなら、気が向いたときに拍手したり、「サブスクライブ」、あるいは「コーヒーをご馳走」って感じで応援してもらえたら嬉しいです。ま、お願いしてる自分もちょっと恥ずかしいですが…。さて、DartやFlutterの開発やってると、そのうち必ずぶつかる問題があるんですよね。でも実際は多くの人がひとまず手探りであれこれ試して—正直、その途中で余計こんがらがっちゃったりもします。この記事では、そのあたりを分かりやすく一度整理しつつ、Dartコンソールで簡単に動かせる例なんかも挟んでみます。あと、話の流れ的に`mixin`とか`mixin class`にもチラッと触れます。正直言うと切り離せないテーマなので、軽くでも押さえておきたいところですね。
## 1. extends: クラシックな継承
まず`extends`を使うタイミングですが、「このクラスって他のクラスからさらに特化させたものだよ」っていうケースですね。Dartの場合、**単一継承**なので拡張できる親クラスは1個だけ(これは大事)。仕組みとしてはJavaとかなり似ていますし、例えば共通部分持ったベースクラス用意しておいて、それを土台に派生クラスを書きたい時、この`extends`が使われます(シンプルだけどわりとハマります)。
## 1. extends: クラシックな継承
まず`extends`を使うタイミングですが、「このクラスって他のクラスからさらに特化させたものだよ」っていうケースですね。Dartの場合、**単一継承**なので拡張できる親クラスは1個だけ(これは大事)。仕組みとしてはJavaとかなり似ていますし、例えば共通部分持ったベースクラス用意しておいて、それを土台に派生クラスを書きたい時、この`extends`が使われます(シンプルだけどわりとハマります)。

implementsによるDartインターフェース活用法を探す
Dartって、`extends`と`implements`の使い分けが実は結構ポイント高いんだよね。眠気覚ましにさっそく例を眺めてみると、C#でよく見かける継承パターン、要は`Dog`が`Animal`から派生して`speak()`を上書きするアレ - まさにこれだ。
void main() {
Dog().speak(); // Bark!
csharp
class Animal {
void speak() => print("Generic sound");
}
css
class Dog extends Animal {
@override
void speak() => print("Bark!");
}
void main() {
Dog().speak(); // Bark!
withを使ってmixinの振る舞いを再利用しよう
Dartだと、すべてのクラスってimplementsキーワードでインターフェース扱いになるんだよね。これ、けっこう便利だけど、「あくまで設計上の型としてしか使えないよ」みたいな気分になる瞬間もある。もちろん、自分の手でメソッドやプロパティをまるっと書き直さなきゃダメなんだ。ま、仕方ないか。
ざっと「implements」について押さえておきたい点を並べてみると―
- 元クラスにどんなメソッド本体があっても、全部自分で再定義しなきゃいけないこと
- 複数のクラスやmixin(ミックスイン)を同時に実装できちゃうあたりは案外自由度高いかも
- Comparable, Iterable, Flutter系だとPreferredSizeWidgetとか、“契約”用途で出番多めかな
- そしてmixinsやmixin classも実装対象になり得る点
こんな雰囲気なんだけど……ちょっと細部はうろ覚え部分もあるかもしれない。それでも、「コード継承じゃなくルール引き受け!」みたいな意識さえあれば困らないはず。
csharp
abstract class Animal {
void speak();
}
css
class RobotDog implements Animal {
@override
void speak() => print("Beep Boop Woof");
}
dart
void main() {
RobotDog().speak(); // Beep Boop Woof
}
上のコード見ればイメージ湧くと思うけど……Animalクラスにもし具体的な実装が入ってたとしても、RobotDog側では中身そのものはもらえないんだわ。「implements」すると、約束事(契約)だけ引き継がれて、コード内容はゼロから書く感じになるんだよね。
ざっと「implements」について押さえておきたい点を並べてみると―
- 元クラスにどんなメソッド本体があっても、全部自分で再定義しなきゃいけないこと
- 複数のクラスやmixin(ミックスイン)を同時に実装できちゃうあたりは案外自由度高いかも
- Comparable, Iterable, Flutter系だとPreferredSizeWidgetとか、“契約”用途で出番多めかな
- そしてmixinsやmixin classも実装対象になり得る点
こんな雰囲気なんだけど……ちょっと細部はうろ覚え部分もあるかもしれない。それでも、「コード継承じゃなくルール引き受け!」みたいな意識さえあれば困らないはず。

mixinとmixin classの違いから学べる新発見を得よう
Mixinという仕組みは、Dartにおいて複数の継承を行わずに再利用できる動作(Behavior Mixins)を実現する手法ですね。たとえば`with`キーワードを使うことで、特定のクラスにメソッド自体とその中身もコピーされるんですよ。普通の「インターフェース」と違い、Mixinには実際の処理を書くことが可能で、`with`で指定すれば、その処理内容ごと使えるようになる感じかな。
ふーん、ちょっとだけコード例も見てみましょうか -
void main() {
Human().walk(); // Walking...
Human().eat(); // Eating...
ふーん、ちょっとだけコード例も見てみましょうか -
csharp
mixin Walks {
void walk() => print("Walking...");
}
css
mixin class Eats {
void eat() => print("Eating...");
}
css
class Human with Walks, Eats {}
void main() {
Human().walk(); // Walking...
Human().eat(); // Eating...
複数mixins適用時のメソッド競合ルールを知ろう
クラスみたいにふるまうけど、ミックスインとしてもそのまま使える、って便利なんだよね。
### メソッド解決順序(MRO)
ミックスインの適用順は**左から右**で、もし複数のミックスインが同じメソッド名を持っていたら、一番右のものが最終的に呼ばれる仕様。これ、「最後のミックスインが優先される」ってだけ覚えておくと良いかも。実際、このルール、3回くらい面接で突っ込まれたことあるから案外大事なんだよな。へえ~って思うかも。
void main() {
C().log(); // M2
}
### ミックスイン内でのsuper
他言語とちょっと違ってて、Dartのミックスインでは`super`が普通に使えるんだよね。ただし、この場合チェーンを逆順で辿る感じになる。だから、ミックスイン内で`super`使ってて`extends`句も絡む時は、結局最後は継承元クラスのメソッドまで到達することになる。ちなみに、この機能をちゃんと動かすためには「on句」でスーパークラス制約付けないとダメ。
void main() {
C().log();
}
出力:
M2
M1
A
_**こんな感じなので、やっぱりミックスインを書く時は順番にも注意したほうがいいです…眠い頭でもこれは意外と忘れないコツ。**_
### メソッド解決順序(MRO)
ミックスインの適用順は**左から右**で、もし複数のミックスインが同じメソッド名を持っていたら、一番右のものが最終的に呼ばれる仕様。これ、「最後のミックスインが優先される」ってだけ覚えておくと良いかも。実際、このルール、3回くらい面接で突っ込まれたことあるから案外大事なんだよな。へえ~って思うかも。
dart
class A {
void log() => print("A");
}
css
mixin M1 {
void log() => print("M1");
}
css
mixin M2 {
void log() => print("M2");
}
css
class C extends A with M1, M2 {}
void main() {
C().log(); // M2
}
### ミックスイン内でのsuper
他言語とちょっと違ってて、Dartのミックスインでは`super`が普通に使えるんだよね。ただし、この場合チェーンを逆順で辿る感じになる。だから、ミックスイン内で`super`使ってて`extends`句も絡む時は、結局最後は継承元クラスのメソッドまで到達することになる。ちなみに、この機能をちゃんと動かすためには「on句」でスーパークラス制約付けないとダメ。
dart
class A {
void log() => print("A");
}
css
mixin M1 on A {
void log() {
print("M1");
super.log();
}
}
css
mixin M2 on A {
void log() {
print("M2");
super.log();
}
}
css
class C extends A with M1, M2 {}
void main() {
C().log();
}
出力:
M2
M1
A
_**こんな感じなので、やっぱりミックスインを書く時は順番にも注意したほうがいいです…眠い頭でもこれは意外と忘れないコツ。**_

superキーワードがmixinsでどう働くか実感する
## コンパイラの制約事項
- `mixin`って、実はコンストラクタが作れないんですよね。
- しかも `on` 制約を付けていないと、`super` の呼び出しもダメだったりします。まあ意外と落とし穴。
- それから、`mixin` 自体を他のクラスで `extend` することは無理ですが、`mixin class` を使えば継承できる仕様になってます。
- 普通のクラスの場合、ちゃんと `mixin class` と宣言してない限りは `with` で混ぜることができません。
- あと、もし `implements` を使ったら――たとえデフォルトの実装がどこかにあったとしても――全部自分でメソッドを上書きしなきゃならないです。ここもちょっと手間。
## 全部盛り!なサンプル
色んな機能を詰め込んだ例、せっかくなので置いときます:
void main() {
final service = MyService();
service.log("Started");
- `mixin`って、実はコンストラクタが作れないんですよね。
- しかも `on` 制約を付けていないと、`super` の呼び出しもダメだったりします。まあ意外と落とし穴。
- それから、`mixin` 自体を他のクラスで `extend` することは無理ですが、`mixin class` を使えば継承できる仕様になってます。
- 普通のクラスの場合、ちゃんと `mixin class` と宣言してない限りは `with` で混ぜることができません。
- あと、もし `implements` を使ったら――たとえデフォルトの実装がどこかにあったとしても――全部自分でメソッドを上書きしなきゃならないです。ここもちょっと手間。
## 全部盛り!なサンプル
色んな機能を詰め込んだ例、せっかくなので置いときます:
dart
abstract class Logger {
void log(String message);
}
css
mixin Timestamped {
void logWithTime(String message) {
final now = DateTime.now().toIso8601String();
print("[$now] $message");
}
}
css
mixin class FileLogger {
void log(String message) => print("File: $message");
}
css
class MyService extends Object with Timestamped implements Logger, FileLogger {
@override
void log(String message) {
logWithTime("Service: $message");
}
}
void main() {
final service = MyService();
service.log("Started");
Dartのコンパイラ制約と注意点に対応しよう
- **`implements`** はインターフェースとしての契約のみを提供し、メソッドの実装(中身)は継承されません。なんかこう、使い道が決まってる感じですね。
- **`with`** は、ミックスインによる振る舞い再利用手法で、もし複数指定して機能が被ったときは、一番最後に指定したものが優先される仕様です。ここも、わりと覚えておいたほうがいいかも。
- **`mixin`** はコンストラクターなしで、クラスとして継承もできないけど、完全に「振る舞い」だけ欲しい時にはピッタリ。まあ便利っちゃ便利。
- **`mixin class`** になると、もうちょっとフレキシブルになってて、ミックスインとしての利用・拡張・実装など全部対応できます。
結局ね、Dartだと `extends` を使ったクラス継承と、`implements` による契約準拠、それに `with` ミックスインって三つのはっきり分かれたやり方があるんですよ。このへん整理しつつ組み合わせれば、無理に基底クラスを肥大化させず柔軟性高く構成できて助かります。Java触ってた人には多分スッと入ってくる構造かなって思います(Javaでも `extends`, `implements` は同じ用法ですよね)。ただね、一つ違うのは Dart には Java には存在しない `with` の概念があります──そこはちょっと独特なんだよなぁ。ま、いいか。
- **`with`** は、ミックスインによる振る舞い再利用手法で、もし複数指定して機能が被ったときは、一番最後に指定したものが優先される仕様です。ここも、わりと覚えておいたほうがいいかも。
- **`mixin`** はコンストラクターなしで、クラスとして継承もできないけど、完全に「振る舞い」だけ欲しい時にはピッタリ。まあ便利っちゃ便利。
- **`mixin class`** になると、もうちょっとフレキシブルになってて、ミックスインとしての利用・拡張・実装など全部対応できます。
結局ね、Dartだと `extends` を使ったクラス継承と、`implements` による契約準拠、それに `with` ミックスインって三つのはっきり分かれたやり方があるんですよ。このへん整理しつつ組み合わせれば、無理に基底クラスを肥大化させず柔軟性高く構成できて助かります。Java触ってた人には多分スッと入ってくる構造かなって思います(Javaでも `extends`, `implements` は同じ用法ですよね)。ただね、一つ違うのは Dart には Java には存在しない `with` の概念があります──そこはちょっと独特なんだよなぁ。ま、いいか。

extends・with・implements組み合わせた活用例を見る
C#とかKotlinを使い慣れてると、Dartのほうが記法がはっきりしてるって感じません?うーん、と言っても、両方の言語で「:」演算子ひとつだけで継承もインターフェース実装もまかなえるんですよね(class MyClass : BaseClass(), MyInterface みたいな書き方)。でもDartは、それぞれの用途ごとに専用キーワードがあって、構造を見た瞬間パッと役割が分かります。地味な違いに見えて、この区別がミックスインとも絡むことで、型システム自体がぐっと柔軟になりつつ理解もしやすくなるんですよ。</code></pre>
あれ、自分、どこか説明漏れてたらすみません。ちょっと寝起きだったので考えながら打ってます笑。質問や意見とか、気になるところは遠慮なくコメント欄に一声どうぞ。その内容を見て記事も順次手直し予定ですから!ブログ内の小さなミスなんかも気づいた人はサクッと指摘してくれるとうれしいですね。もしこの投稿よかったと思ったなら、「拍手」押してもらえればなおハッピー……ま、いいか。
DartとJavaやC#との型システム違いを比較してみよう
LinkedInかStackOverflowのどちらかでメッセージいただけたらうれしいです。まぁ、起きてるときなら大体すぐ反応できるかな……!:P
## コミュニティのみなさん、本当にありがとう
_帰る前にちょっとだけ:_
👉 もしよかったら著者に**拍手**&**フォロー**をぽちっとお願いします️👏
👉 フォローはこのへんから:**X** | **Medium**
👉 CodeToDeploy Tech Community、実はDiscordでも公開してます—よければ遊びにきてください!
👉 そうだ、**CodeToDeploy出版物も要チェックですよ~**
_※ちなみに、この投稿にはアフィリエイトリンクが含まれている場合もあるので、その点ご留意を。_
## コミュニティのみなさん、本当にありがとう
_帰る前にちょっとだけ:_
👉 もしよかったら著者に**拍手**&**フォロー**をぽちっとお願いします️👏
👉 フォローはこのへんから:**X** | **Medium**
👉 CodeToDeploy Tech Community、実はDiscordでも公開してます—よければ遊びにきてください!
👉 そうだ、**CodeToDeploy出版物も要チェックですよ~**
_※ちなみに、この投稿にはアフィリエイトリンクが含まれている場合もあるので、その点ご留意を。_