0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オブジェクト指向~カプセル化~

Posted at

おはようございます。こんにちは。こんばんは。

本日はオブジェクト指向のカプセル化という概念について記事を執筆します。

カプセル化とは

カプセル化の定義を確認します。
Gemini2.5に聞いてみました。

image.png

geminiによればデータを直接操作をしてはいけないということが言いたいようです。

例を示して説明します。
財布クラスにお金というフィールドを設定します。カプセル化という概念を使用しない場合はフィールドを直接操作する必要があります。

ソースコードで示します。

まずダメな例

Wallet.java
public class Wallet {
    // 財布に入っているお金
    public int money;

続いて実行用ファイル

Test.java

public class Test {
    public static void main(String[] args){
        Wallet wallet = new Wallet();
        // 財布のお金に1000円を設定する。
        wallet.money = 1000;
        // 財布のお金に500円を設定する。
        wallet.money = 500;
        System.out.println(wallet.money);
    }
}

実行します。

500

一見良さそうではあります。
が、このコードには問題があります。
例えば以下のようなことができてしまいます。

Test.java
public class Test {
    public static void main(String[] args){
        Wallet wallet = new Wallet();
        // 財布のお金に1000円を設定する。
        wallet.money = 1000;
        // 財布のお金に500円を設定する。
        wallet.money = 500;
        wallet.money = -100;
        System.out.println(wallet.money);
    }
}

実行結果

-100

なんと財布の中のお金にマイナスの額を設定できてしまいました。このようにフィールドを直接操作すると意図しない額を誤って設定してしまうなどのコーディングミスが誘発されます。

続いてカプセル化を実現したソースコードを示します。

Wallet.java
public class Wallet {   
    // 財布に入っているお金
    // アクセス修飾子をprivateに設定する。
    private int money;

    // コンストラクタ
    public Wallet(int money){
        this.money = money;
    }

    // 財布に入っているお金から引数の額分お金を取り出す
    public void takeOut(int amountToTakeOut){
        // 引数の妥当性チェック
        // 取り出すお金が残高より少ない場合に取り出し可能
        if(amountToTakeOut > 0 && money > amountToTakeOut){
            money -= amountToTakeOut;
        } else {
            System.out.println("お金を取り出すことができません");
        }
    }

    // 財布にお金を追加する。
    public void add(int amountToAdd){
        // 引数の妥当性チェック
        if(amountToAdd > 0){
            money += amountToAdd;
        } else {
            System.out.println("マイナスの額は追加できません");
        }
    }

    // 財布に入っているお金をすべて取り出す
    public int getMoney(){
        return money;
    }
}

財布というクラスにmoneyフィールドと財布の中のmoneyを出し入れするメソッド、そして財布の中にあるmoneyを確認するメソッドを定義しました。
そしてmoneyフィールドにはアクセス修飾子をprivateに、フィールドを操作するメソッドにはpublicを設定します。
※今回はpublicとしましたが、メソッドのアクセス修飾子は要件に応じて適切に設定してください。

実行用ファイルです。

Test.java
public class Test {
    public static void main(String[] args){
        Wallet wallet = new Wallet(1000);
        wallet.add(1000);
        wallet.takeOut(500);
        wallet.add(-100);
        System.out.println(wallet.getMoney());
    }

実行結果

マイナスの額は追加できません
1500

正しい実行結果となりました。不正値を追加することもできなくなりました。
上記では
1.フィールドのアクセス修飾子をprivateにする
2.フィールドを操作するときはメソッド※1を通じて操作する

ということを行いました。
以上がカプセル化の概念になります。

カプセル化には

1.安全性の向上(外部から不正にフィールドが変更されることを防ぐ)
2.保守性の向上(仕様変更時やデバッグ時にはメソッドの一部分を修正すれば良いので変更の影響を局所化できる。)
のようなメリットがあります。(他にもテスト容易性や再利用性の向上などのメリットもあります。)

※1
フィールドの値を取得する「get+フィールド名」のように定義するメソッド名をgetterといいます。(サンプルでは財布に入っている額を参照するメソッドであるgetMoneyメソッドを定義しています。)
一方でフィールドの値を設定するset+フィールド名のように定義するメソッド名を setter といいます。(今回addメソッドやtakeOutメソッドでフィールドを操作しているのでsetterは定義していません。)
getterとsetterを合わせてアクセサメソッドと呼びます。

まとめ

まとめます。

クラスを設計する際は
1.フィールドをprivateに設定する
2.フィールドの値を設定・取得するメソッド(通常get+フィールド名、set+フィールド名)を定義し、メソッド経由でフィールドの操作を行う。
ことを意識しましょう。
上記を実現することで、プログラムの安全性と保守性の向上を実現してください。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?