セッターでのバリデーション
CoddyのCジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 20/61。
前のレッスンでは、値を単純に代入する基本的なセッターを作成しました。しかし、これではカプセル化の重要な利点である、検証ロジックを追加してデータを保護する機能が活かされていません。
負の値になってはいけない Counter を考えてみましょう。カプセル化されていなければ、誰でも c->value = -50 と書いて状態を壊せてしまいます。setter を使えば、どの値を許可するかを制御できます。
// counter.c
void counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return; // 無効な入力を静かに拒否する
}
c->value = new_value;
}これで負の値は単純に無視されます。
成功または Failure を示すステータスコードを返すことを選択する場合もあります。
int counter_set_value(Counter *c, int new_value) {
if (new_value < 0) {
return 0; // 失敗
}
c->value = new_value;
return 1; // 成功
}このパターンにより、呼び出し元は操作が成功したかどうかを知ることができます。重要な点は、setter は単なる代入のためのものではないということです。setter は、オブジェクトの状態がどのようなものであり得るかについてのルールを適用する門番なのです。これがカプセル化の真の力です。外部コードが何をしようとしても、オブジェクトは自分自身の整合性を維持します。
チャレンジ
簡単セッターでの検証を使ってデータを保護する Temperature モジュールを構築しましょう。妥当な範囲内の値のみを受け付ける温度トラッカーを作成し、セッターがオブジェクトの状態を守る門番として機能する方法を示します。
3つのファイルを作成します。
temperature.h: opaque pointer パターンを使用した公開インターフェースです。前方宣言のみでTemperature型を Declare します。次の関数を Declare します。create_temperature: initial degrees 用の整数を受け取り、Temperature ポインターを返しますfree_temperature: allocated memory を解放しますtemp_get_degrees: 現在の温度値を返す Getter ですtemp_set_degrees:int(成功時は1、failure 時は0)を返す Setter です
TEMPERATURE_Hを使って include guards を設定します。temperature.c: hidden なint degreesmember を持つ実際のstruct Temperatureを Define します。すべての関数を Implement します。重要なのは Setter です。-50 以上 150 以下(inclusive)の値のみを accept する必要があります。値がこの範囲外の場合は0を返し、温度を変更せずに leave します。valid の場合は値を更新して1を返します。main.c: valid と invalid の両方の温度を設定しようとすることで検証を実演し、invalid の値が拒否され、valid な値が受け入れられることを示します。
3つの入力を受け取ります。initial temperature、設定する範囲内の valid temperature、そして試行する範囲外の invalid temperature です。
main ファイルで、initial value を使って Temperature を作成し、それを出力します。次に、invalid temperature は拒否されるはずなので、その設定を試み、結果を出力して値が変更されていないことを示します。最後に valid temperature を設定し、成功結果を出力して更新された値を示します。memory を Free して cleanup を確認します。
次の形式で出力します。
Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
Freedたとえば、入力が 25、100、200 の場合、出力は次のようになります。
Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
Freedこれはカプセル化の真の力を示しています。Setter が valid temperature の条件に関するルールを強制するため、外部コードがどのような値を assign しようとしても、オブジェクトの整合性が保護されます。
自分で試してみよう
#include <stdio.h>
#include "temperature.h"
int main() {
// 入力を読み取る
int initial, valid_temp, invalid_temp;
scanf("%d", &initial);
scanf("%d", &valid_temp);
scanf("%d", &invalid_temp);
// TODO: 初期値でTemperatureを作成する
// TODO: 初期温度を出力する
// 形式: "Initial: {degrees}"
// TODO: 無効な温度の設定を試みる
// 結果を出力し、値が変更されていないことを示す
// 形式: "Set {invalid}: {0 or 1}"
// Format: "After invalid: {degrees}"
// TODO: 有効な温度を設定する
// 成功結果を出力し、更新された値を示す
// 形式: "Set {valid}: {0 or 1}"
// 形式: "After valid: {degrees}"
// TODO: メモリを解放し、"Freed"を出力する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Cオンラインコンパイラ