【オブジェクト指向】カプセル化とは何か?現役SEが分かりやすく解説します!

encapsulation IT
encapsulation

こんにちは、現役SEのゆとです。

オブジェクト指向には様々な要素が兼ね備えられており、非常に奥の深いものであるといえます。

特にその中でも、オブジェクト指向の3大要素といわれている要素があります。それが「カプセル化」、「継承」、「ポリモーフィズム」です。

ゆと
ゆと

この3つの要素はオブジェクト指向を利用する上で非常に重要です。

私も最初は苦労して覚えました笑

今回はその中からカプセル化について解説していきます。

現役SEの私が、初心者の方にも分かりやすく解説していきますので、ぜひ最後まで読んでいただきたいです。それではどうぞ!

カプセル化とは?

カプセル化とは、オブジェクトの内部情報(フィールドやメソッド)やクラスそのものを隠し、外部からのアクセスを制限することです。

オブジェクト指向言語を使った開発を行う上で、オブジェクトの内部情報がどこからでも操作できてしまうことは、あまり良くない実装となります。

例えば、車のクラスを考えるとしましょう。この車クラスには、車種や燃費、走行距離などのフィールドがあるとします。車クラスのオブジェクトを生成するために、インスタンス化する必要がありますが、その際にフィールドに対して具体的な値を与えることになります。

クラスやインスタンスに関しては、こちらの記事をご覧ください。

その時、アクセスを制限することを考えていないと、走行距離を現実ならありえない-5万kmなんていうマイナスの値にしてみたり、1,000万kmなんていうとてつもなく大きな値で設定できてしまいます。このような値は実装上エラーは起こらずとも、現実的に考えて適切な値とはいえません。

またオブジェクトへのアクセスに制限をかけていないと、内部情報に変更が生じた場合、外部からアクセスしている様々なオブジェクトに影響が出てしまいます。

このような問題を防ぐために、カプセル化は有効な要素となります。カプセル化によってオブジェクトの内部情報を隠蔽し、外部からのアクセスを制御することによって、オブジェクトの安全性保守性を高めることができます。

encapsulation
カプセル化

アクセス制御

上でお話ししたような、オブジェクトの内部情報やクラスそのものを隠したり公開したりすることを、アクセス制御といいます。

メンバ(フィールドとメソッド)に対するアクセス制御には4つのレベルがあり、そのレベルはキーワードを用いて指定することができます。このキーワードのことをアクセス修飾子といいます。

accesscontrol1
メンバに対するアクセス制御

またクラスに対するアクセス修飾子は以下の通りになっています。

accesscontrol2
クラスに対するアクセス制御

アクセス制御は時と場合によって最適なレベルを選ぶことが適切です。ただ、どれを選べば良いかわからない場合は、定石として

  • フィールドは全てprivate
  • メソッドは全てpublic

というようにすると良いとされています。
クラスに対するアクセス制御の定石としては、全てpublicで指定することとされています。

ゆと
ゆと

実際にはそのメンバやクラスに合った、適切なレベルを設定してあげてください!

フィールドの操作方法

アクセス制御についての解説では、フィールドは全てprivateで指定することが定石とお話ししました。

ただそれだと、外部からフィールドの読み書きを行うことが一切できなくなります。

そのため外部からフィールドの読み書きを行う際は、自クラス内のメソッドを経由して行われます。この時使われるメソッドのことを、getterメソッド、setterメソッドと呼びます。

getterメソッドは、外部からフィールドの値を取得したい時に使われます。例えば走行距離のフィールドに対して、getterメソッドを定義する場合、以下のようになります。

public class Car(){
    // 走行距離フィールド定義
    private int mileage;

    // getterメソッド定義
    public int getMileage(){
        return this.mileage;
    }
}

基本的に、getterメソッドのメソッド名は「”get” + フィールド名」というようにします。
コードの通り、getterメソッドは呼び出されたらそのフィールドの値をそのまま返すという役割を担っています。

次にsetterメソッドです。setterメソッドは、外部からフィールドの値を操作したい時に使われます。こちらも走行距離フィールドに対して、setterメソッドを定義してみます。

public class Car(){
    // 走行距離フィールド定義
    private int mileage;

    // setterメソッド定義
    public void setMileage(int mileage){
        this.mileage = mileage;
    }
}

setterメソッドも、メソッド名は「”set” + フィールド名」というようにします。
コードの通り、setterメソッドを呼び出す際は設定したい値を引数として渡してあげます。そして、その値をフィールドに代入することで、フィールド操作が実現します。

また上で述べたように、フィールドに現実では考えられない値が入力されてしまう可能性がある場合は、setterメソッド内で値の妥当性をチェックします。こうすることで、フィールドに不適切な値が設定されることを防ぐことができます。

public class Car(){
    // 走行距離フィールド定義
    private int mileage;

    // setterメソッド定義
    public void setMileage(int mileage){
        // 走行距離がマイナスの値の時
        if (mileage < 0){ 
            System.out.println("走行距離が不適切です。");
        }

        if (mileage >= 0){ 
            this.mileage = mileage;
        }
    }
}

このようにgetter/setterメソッドを使うことで、外部からフィールドの値を直接読み書きされることを防ぐことができます。

まとめ

今回はオブジェクト指向におけるカプセル化について解説しました。

安全で保守性の高いシステムを開発するためにも、情報のアクセスにあえて制限をかけるということが重要でしたね。

当ブログでは他にも様々なITに関係する情報を発信しています。よろしければご覧ください。

最後までご覧いただきありがとうございました。それではまた!

コメント

タイトルとURLをコピーしました