Menu
Coddy logo textTech

ライブラリレベルのプライバシー

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);           // 動作します - 公開ゲッターを使用
}

このライブラリレベルのプライバシーは、同じファイル内のクラスが密接に連携できる一方で、外部のコードからは実装の詳細を隠蔽できることを意味します。これは、関連するクラスを同じライブラリ内にまとめて整理することを促す、意図的な設計上の選択です。

challenge icon

チャレンジ

簡単

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 に直接アクセスできないことを再確認するためのものです)。

ここでの重要な洞察は、TeamLeadMember のプライベートな _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 とは別のライブラリにあるためです
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン