ライブラリレベルのプライバシー
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 32/110。
Dartでは、プライバシーはクラスレベルではなく、ライブラリレベルで適用されます。これはJavaやC++といった言語との大きな違いです。Dartにおけるライブラリは、通常は単一のファイル、またはpartディレクティブで接続された複数のファイルです。
プライベートメンバ(_で始まるもの)は、同じライブラリ内であれば、他のクラスからでもどこからでもアクセス可能です。
// 両方のクラスが同じファイル(同じライブラリ)内にある
class Engine {
int _horsepower = 200; // このライブラリに対してプライベート
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // アクセス可能!同じライブラリ内
}
}しかし、別のファイルからクラスをインポートすると、そのプライベートメンバは完全に隠蔽されます:
// ファイル: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// ファイル: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // エラー!アクセスできません
print(engine.power); // 動作します - 公開ゲッターを使用
}このライブラリレベルのプライバシーは、同じファイル内のクラスが密接に連携できる一方で、外部のコードからは実装の詳細を隠蔽できることを意味します。これは、関連するクラスを同じライブラリ内にまとめて整理することを促す、意図的な設計上の選択です。
チャレンジ
簡単Dartにおけるライブラリレベルのプライバシーがどのように機能するかを示す、チームコラボレーションシステムを構築しましょう。同じファイル内のクラスが互いのプライベートメンバにアクセスできる一方で、別のファイルにあるコードからはアクセスできない様子を確認します。
コードを2つのファイルに整理します:
team.dart: このファイルには、同じライブラリ内で密接に連携する2つのクラスを含めます:Memberクラス:パブリックなString nameと、50で初期化されたプライベートなint _performanceScoreを持ちます。名前を受け取るコンストラクタと、プライベートなスコアを返すパブリックなゲッターperformanceScoreを含めてください。- 同じファイル内の
TeamLeadクラス:Memberのプライベートフィールドに直接アクセスできます(同じライブラリ内にあるため)。このクラスは、パブリックなString name、名前を受け取るコンストラクタ、およびmember._performanceScoreに直接アクセスして10を加え、[leadName] boosted [memberName]'s score to [newScore]と出力するメソッドevaluateMember(Member member)を持つ必要があります。
main.dart: チームファイルをインポートし、アクセスの違いを実演します:'Alice'という名前のMemberを作成します。'Bob'という名前のTeamLeadを作成します。- Aliceのパブリックゲッターを使用して
Initial score: [score]と出力します。 - Bobに
evaluateMemberを使ってAliceを評価させます。 - パブリックゲッターを使用して
Updated score: [score]と出力します。 Direct access from main: Not allowedと出力します(これは、main.dartが別のライブラリにあるため、_performanceScoreに直接アクセスできないことを再確認するためのものです)。
ここでの重要な洞察は、TeamLead は Member のプライベートな _performanceScore を直接読み取って変更できるということです。なぜなら、両方のクラスが同じファイル(同じライブラリ)に存在するためです。しかし、main.dart のコードは別のライブラリにあるため、パブリックなゲッターを使用する必要があります。
期待される出力:
Initial score: 50
Bob boosted Alice's score to 60
Updated score: 60
Direct access from main: Not allowedチートシート
Dartでは、プライバシーはクラスレベルではなくライブラリレベルで適用されます。ライブラリは通常、単一のファイル、またはpartディレクティブで接続された複数のファイルです。
プライベートメンバはアンダースコア(_)で始まり、同じライブラリ内であれば、他のクラスからでもどこからでもアクセスできます:
// 両方のクラスが同じファイル内(同じライブラリ)にある
class Engine {
int _horsepower = 200; // このライブラリに対してプライベート
}
class Car {
void showPower(Engine engine) {
print(engine._horsepower); // アクセス可能!同じライブラリ
}
}別のファイルからクラスをインポートすると、そのプライベートメンバは非表示になります:
// ファイル: engine.dart
class Engine {
int _horsepower = 200;
int get power => _horsepower;
}
// ファイル: main.dart
import 'engine.dart';
void main() {
var engine = Engine();
// print(engine._horsepower); // エラー!アクセス不可
print(engine.power); // 動作する - 公開ゲッターを使用
}この設計は、関連するクラスを同じライブラリにまとめて整理することを推奨しており、外部コードから実装の詳細を隠しながら、クラス同士が密接に連携できるようにします。
自分で試してみよう
import 'team.dart';
void main() {
// TODO: 'Alice' という名前の Member を作成する
// TODO: 'Bob' という名前の TeamLead を作成する
// TODO: Alice の公開ゲッターを使用して "Initial score: [score]" を出力する
// TODO: evaluateMember を使用して Bob に Alice を評価させる
// TODO: 公開ゲッターを使用して "Updated score: [score]" を出力する
// TODO: "Direct access from main: Not allowed" を出力する
// Note: ここでは alice._performanceScore にアクセスできません。なぜなら
// main.dart が team.dart とは別のライブラリにあるためです
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ