Menu
Coddy logo textTech

セッターでのバリデーション

CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 20/61。

前のレッスンでは、単に値を代入するだけの基本的なセッターを作成しました。しかし、これではカプセル化の主要な利点である、バリデーション(検証)ロジックを追加してデータを保護するという機能が欠けています。

Counterが負の値にならないようにすることを考えてみましょう。カプセル化がないと、誰でもc->value = -50と書き込むことができ、状態を壊してしまう可能性があります。セッターを使用すると、許可される値を制御できます。

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // 無効な入力を暗黙的に拒否する
    }
    c->value = new_value;
}

これで、負の値は単に無視されるようになります。

成功または失敗を示すために、ステータスコードを返すこともできます。

int counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return 0;  // 失敗
    }
    c->value = new_value;
    return 1;  // 成功
}

このパターンは、操作が成功したかどうかを呼び出し元に知らせます。重要な洞察は、セッターは単なる代入のためのものではなく、オブジェクトの状態がどうあるべきかというルールを強制するゲートキーパーであるということです。これがカプセル化の真の力です。外部のコードが何をしようとしても、オブジェクトは自らの整合性を維持します。

challenge icon

チャレンジ

簡単

セッターでのバリデーションを使用してデータを保護する Temperature モジュールを構築しましょう。有効な範囲内の値のみを受け入れる温度トラッカーを作成し、セッターがオブジェクトの状態に対するゲートキーパーとしてどのように機能するかを実証します。

3つのファイルを作成します:

  • temperature.h: 不透明ポインタ(opaque pointer)パターンを使用したパブリックインターフェースです。前方宣言のみを使用して Temperature 型を宣言します。以下の関数を宣言してください:
    • create_temperature — 初期の度数を整数で受け取り、Temperature ポインタを返します
    • free_temperature — 割り当てられたメモリを解放します
    • temp_get_degrees — 現在の温度値を返すゲッターです
    • temp_set_degreesint を返すセッターです(成功時は 1、失敗時は 0)
    シンボル TEMPERATURE_H を使用したインクルードガードを使用してください。
  • temperature.c: 隠蔽された int degrees メンバを持つ実際の struct Temperature を定義します。すべての関数を実装してください。鍵となるのはセッターです。-50 から 150(両端を含む)の間の値のみを受け入れる必要があります。値がこの範囲外の場合は、0 を返し、温度は変更しないままにします。有効な場合は、値を更新して 1 を返します。
  • main.c: 有効な温度と無効な温度の両方の設定を試みることでバリデーションを実証し、無効な値は拒否され、有効な値は受け入れられることを示します。

3つの入力を受け取ります:初期温度、設定する有効な温度(範囲内)、および試行する無効な温度(範囲外)です。

メインファイルで、初期値を使用して Temperature を作成し、それを表示します。次に、無効な温度の設定を試みます。これは拒否されるはずなので、結果を表示し、値が変更されていないことを示します。最後に、有効な温度を設定し、成功の結果を表示して、更新された値を表示します。メモリを解放し、クリーンアップを確認します。

出力を以下の形式で表示してください:

Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
Freed

例えば、入力が 25100200 の場合、出力は以下のようになります:

Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
Freed

これはカプセル化の真の力を示しています。セッターが有効な温度を構成するルールを強制し、外部コードがどのような値を割り当てようとしても、オブジェクトの整合性を保護します。

チートシート

セッターには、データの整合性を保護するためのバリデーション(検証)ロジックを含めることができます。単に値を代入するのではなく、オブジェクトの有効な状態に関するルールを強制するゲートキーパーとして機能します。

基本的なバリデーションの例 - 無効な入力を黙って拒否する:

void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // 無効な入力を拒否
    }
    c->value = new_value;
}

成功または失敗を示すステータスコードを返す:

int counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return 0;  // 失敗
    }
    c->value = new_value;
    return 1;  // 成功
}

このパターンにより、呼び出し側は操作が成功したかどうかを確認できるようになり、外部コードの試行に関わらず、オブジェクトが自らの整合性を維持することが可能になります。

自分で試してみよう

#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: initial の値で Temperature を作成する
    
    // TODO: 初期の温度を表示する
    // 形式: "Initial: {degrees}"
    
    // TODO: 無効な温度の設定を試みる
    // 結果を表示し、値が変更されていないことを示す
    // 形式: "Set {invalid}: {0 or 1}"
    // 形式: "After invalid: {degrees}"
    
    // TODO: 有効な温度を設定する
    // 成功の結果を表示し、更新された値を示す
    // 形式: "Set {valid}: {0 or 1}"
    // 形式: "After valid: {degrees}"
    
    // TODO: メモリを解放し、"Freed" と表示する
    
    return 0;
}
quiz icon腕試し

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

Object Oriented Programmingのすべてのレッスン