Menu
Coddy logo textTech

Getter と Setter の詳細

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 33/110。

ゲッターとセッターは、プライベートフィールドと組み合わせることで、カプセル化のための強力なツールになります。これらを使用すると、データのアクセスや変更方法を完全に制御しながら、クリーンなパブリックインターフェースを公開できます。

一般的なパターンは、プライベートフィールドを、バリデーション(検証)を含む公開のゲッターおよびセッターと組み合わせることです。

class Temperature {
  double _celsius = 0;
  
  double get celsius => _celsius;
  
  set celsius(double value) {
    if (value < -273.15) {
      _celsius = -273.15;  // 絶対零度が最小値
    } else {
      _celsius = value;
    }
  }
}

セッターはビジネスルールを適用し、オブジェクトが不正な状態にならないようにすることができます。

プライベートデータから値を派生させる計算ゲッターを作成することもできます:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;      // 計算値
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

読み取り専用のアクセスが必要な場合があります。その場合は、セッターを定義せずにゲッターだけを提供します。

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;  // 読み取り専用
}

このパターンは、外部コードにデータへの可視性を提供しながら、いかなる変更も防ぎます。プライベートフィールドとゲッターのみを組み合わせることで、真の読み取り専用アクセスが実現します。

challenge icon

チャレンジ

簡単

データアクセスを制御するためのゲッターとセッターの威力を示す、製品在庫システムを構築しましょう。内部データを保護しながら、計算プロパティとバリデーションを提供するクラスを作成します。

コードを2つのファイルに整理します:

  • product.dart: 適切なカプセル化を行って在庫を管理する Product クラスを定義します。製品には以下のものを含める必要があります:
    • パブリックな String name
    • プライベートな double _price
    • プライベートな int _quantity
    • これら3つの値を受け取るコンストラクタ
    • プライベートな価格を返すゲッター price
    • 0 より大きい値のみを受け入れるセッター price(無効な値は無視する)
    • プライベートな数量を返すゲッター quantity
    • 0 以上の値のみを受け入れるセッター quantity(負の値は無視する)
    • _price * _quantity を返す計算ゲッター totalValue
    • 数量が 0 より大きい場合に true を返す計算ゲッター isInStock
    • 名前の最初の3文字を大文字にし、その後に数量を続けたシンプルなSKUを生成する読み取り専用ゲッター sku(例:数量25の "Laptop" の場合は LAP25
    • 製品の詳細を表示するメソッド displayProduct()
  • main.dart: 製品クラスをインポートし、ゲッターとセッターがどのようにアクセスを制御するかを示します:
    • 名前が 'Laptop'、価格が 999.99、数量が 25 の製品を作成します
    • displayProduct() を呼び出します
    • In stock: [isInStock] を出力します
    • SKU: [sku] を出力します
    • 価格を -50.0 に設定しようとします(無視されるはずです)
    • 価格を 899.99 に設定します(有効な変更)
    • 数量を -10 に設定しようとします(無視されるはずです)
    • 数量を 0 に設定します(有効な変更)
    • displayProduct() を呼び出します
    • In stock: [isInStock] を出力します
    • SKU: [sku] を出力します

displayProduct() メソッドは、以下の形式で出力する必要があります:

--- Product Info ---
Name: [name]
Price: $[price]
Quantity: [quantity]
Total Value: $[totalValue]

期待される出力:

--- Product Info ---
Name: Laptop
Price: $999.99
Quantity: 25
Total Value: $24999.75
In stock: true
SKU: LAP25
--- Product Info ---
Name: Laptop
Price: $899.99
Quantity: 0
Total Value: $0.0
In stock: false
SKU: LAP0

チートシート

ゲッターとセッターをプライベートフィールドと組み合わせることで、カプセル化とデータアクセスへの制御が可能になります。

ゲッターとセッターを持つプライベートフィールド

class Temperature {
  double _celsius = 0;
  
  double get celsius => _celsius;
  
  set celsius(double value) {
    if (value < -273.15) {
      _celsius = -273.15;
    } else {
      _celsius = value;
    }
  }
}

計算されたゲッター

ゲッターはプライベートデータから値を派生させることができます:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

読み取り専用アクセス

読み取り専用プロパティには、セッターなしのゲッターを提供します:

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;
}

自分で試してみよう

import 'product.dart';

void main() {
  // TODO: 名前が 'Laptop'、価格が 999.99、数量が 25 の製品を作成してください

  // TODO: displayProduct() を呼び出してください

  // TODO: "In stock: [isInStock]" を出力してください

  // TODO: "SKU: [sku]" を出力してください

  // TODO: 価格を -50.0 に設定してみてください(無視されるはずです)

  // TODO: 価格を 899.99 に設定してください(有効な変更)

  // TODO: 数量を -10 に設定してみてください(無視されるはずです)

  // TODO: 数量を 0 に設定してください(有効な変更)

  // TODO: displayProduct() を呼び出してください

  // TODO: "In stock: [isInStock]" を出力してください

  // TODO: "SKU: [sku]" を出力してください
}
quiz icon腕試し

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

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