Java入門|メソッドを公開して安全に操作するしくみ

中身は守り、使い方は開く。public メソッドがあると、クラスは安全で使いやすい部品になる

private を学ぶと、「大事なフィールドは外から直接触れないように隠せばよい」という感覚が見えてきます。これはとても大切な第一歩です。ですが、フィールドを隠しただけでは、今度はクラスの外から必要な設定すらできなくなってしまいます。戦士の情報を守りたいのに、名前も戦闘力も気の量もまったく設定できないのでは、クラスを実際のプログラムで使うことが難しくなってしまいます。

そこで登場するのが、public メンバです。ドラゴンボールで考えるなら、戦士の内部状態そのものは勝手に触らせないようにしながら、「正しい手順で状態を変えるための技」だけは外に公開しておくイメージです。たとえば気の量を設定するときも、外からいきなり energy に値を入れさせるのではなく、専用のメソッドを通して、正しい値かどうかを確認してから反映するようにできます。ここでは、private と public をどう使い分けるのか、そしてその考え方がどうカプセル化につながるのかを、ドラゴンボールのたとえでやさしく整理していきます。

private だけでは、安全でも使いにくい

前回学んだように、フィールドを private にすると、クラスの外から直接アクセスできなくなります。
たとえば Saiyan クラスのフィールドを次のようにしたとします。

class Saiyan
{
    private String name;
    private int power;
    private double energy;
}

このようにしておけば、main メソッドのようなクラスの外側からは、

goku.name = "悟空";
goku.power = 9000;
goku.energy = -10.0;

のような直接代入はできなくなります。

これはとても安全です。
でもその一方で、

  • 正しい名前を設定したい
  • 正しい戦闘力を設定したい
  • 正しい気の量を設定したい

という普通の操作までできなくなってしまいます。

つまり private は、中身を守る力は強いけれど、それだけでは「安全に使う方法」がまだ足りない状態なのです。

そこで必要になるのが public メソッド

この問題を解決するために使うのが public メソッドです。

public をつけたメンバは、クラスの外から利用できます。
つまり、フィールドは private で守りつつ、必要な操作だけを public メソッドとして公開すればよいわけです。

ドラゴンボールで言えば、

  • 戦士の内部データそのものは非公開
  • でも正式な手順で気を整える技や、状態を表示する技は公開

という設計です。

この考え方を使うと、外からは「決められた安全な入口」だけを通して操作できるようになります。
これが、クラスを安全で使いやすい部品にしていく基本の発想です。

直接代入ではなく、専用メソッドを通して設定する

では、実際にどう書くのかを見てみましょう。
今回の考え方をドラゴンボールの世界に置きかえて、プログラムを整理すると次のようになります。

ファイル名:Sample2.java

class Saiyan
{
    private String name;
    private int power;
    private double energy;

    public void setStatus(String n, int p, double e)
    {
        if (e > 0 && e < 1000) {
            name = n;
            power = p;
            energy = e;
            System.out.println("戦士の名前を" + name + "に戦闘力を" + power + "に気の量を" + energy + "にしました。");
        }
        else {
            System.out.println(e + "は正しい気の量ではありません。");
            System.out.println("気の量を変更できませんでした。");
        }
    }

    public void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("気の量は" + energy + "です。");
    }
}

class Sample2
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();

        // goku.name = "悟空";
        // goku.power = 9000;
        // goku.energy = -10.0;

        goku.setStatus("悟空", 9000, 20.5);
        goku.show();

        System.out.println("正しくない気の量(-10.0)を指定してみます・・・");

        goku.setStatus("悟空", 9000, -10.0);
        goku.show();
    }
}

このコードでは、name、power、energy は private なので、外から直接触れません。
その代わりに、setStatus() と show() が public になっています。

つまり、クラスの外からは

  • setStatus() で状態を設定する
  • show() で状態を表示する

という安全な使い方だけができるようになっています。

public メソッドの中で値をチェックできる

このサンプルのいちばん大事な点は、setStatus() の中で、値が正しいかどうかをチェックしているところです。

if (e > 0 && e < 1000) {
    name = n;
    power = p;
    energy = e;
    ...
}
else {
    ...
}

ここでは、気の量 e が 0 より大きく、1000 より小さいときだけ、energy に代入しています。
つまり、正しい範囲の値だけを受け入れるようにしているわけです。

もし不正な値が渡されたら、energy は変更しません。
これがとても大切です。

以前のように外から直接

goku.energy = -10.0;

と書けてしまうなら、防ぎようがありませんでした。
でも今は必ず setStatus() を通るので、その中でチェックできます。

ドラゴンボールで言えば、戦士の気を調整するときに、必ず「この値は自然な範囲か」を確認してから反映しているようなものです。

誤った値を防げるので、安全性が上がる

この設計のよいところは、外からどんな値が渡されても、クラス自身が最終チェックをできるところです。

たとえば、

goku.setStatus("悟空", 9000, 20.5);

なら、20.5 は正しい値なので設定されます。

でも、

goku.setStatus("悟空", 9000, -10.0);

なら、-10.0 は不正な値なので設定されません。

実行結果のイメージはこうなります。

戦士の名前を悟空に戦闘力を9000に気の量を20.5にしました。
戦士の名前は悟空です。
戦闘力は9000です。
気の量は20.5です。
正しくない気の量(-10.0)を指定してみます・・・
-10.0は正しい気の量ではありません。
気の量を変更できませんでした。
戦士の名前は悟空です。
戦闘力は9000です。
気の量は20.5です。

最後の show() を見ると、気の量は 20.5 のままです。
つまり、不正な値はクラスの中に入らなかったわけです。

このように、public メソッドを入口にして、そこで値を確認することで、クラスの安全性はかなり高まります。

private と public を使い分けるのが大切

ここで大事なのは、private と public は対立するものではなく、役割分担して一緒に使うものだということです。

表で整理するとこうなります。

修飾子役割
privateクラスの外から直接触らせない
publicクラスの外から使えるように公開する

そして、よくある基本形は次のようになります。

メンバの種類よくある設計
フィールドprivate
メソッドpublic

つまり、

  • データそのものは守る
  • 操作方法だけを公開する

という形です。

ドラゴンボールで言えば、

  • 戦士の内部状態は守る
  • 状態を変える正式な技だけ外に見せる

という考え方です。

この使い分けが、クラス設計のとても重要な基本になります。

カプセル化とは何か

ここで出てくる大切なキーワードが、カプセル化です。

カプセル化とは、
データと機能をひとまとめにし、必要に応じてメンバを保護すること
です。

今回の Saiyan クラスで考えると、

  • name、power、energy というデータがある
  • setStatus()、show() という機能がある
  • データは private で守っている
  • 機能は public で公開している

という構造になっています。

これがまさにカプセル化の考え方です。

ドラゴンボールでたとえるなら、戦士の大事な中身をカプセルの中に入れて守り、外からは決められた操作口だけを使わせるイメージです。
だから「カプセル化」という言葉は、とても感覚に合っています。

カプセル化のよいところ

カプセル化のよいところは、クラスを使う人が、危ない使い方をしにくくなることです。

たとえば、Saiyan クラスを設計する人と、それを使って別のプログラムを書く人が別々だったとします。
そのとき、フィールドが全部丸見えで自由に触れる設計だと、使う人はうっかり不自然な値を入れてしまうかもしれません。

でも、

  • フィールドは private
  • 安全な操作メソッドだけ public

という設計にしておけば、使う人はその公開された使い方に従うだけで、自然な範囲の操作をしやすくなります。

つまりカプセル化は、
クラスを作る人にも、クラスを使う人にもやさしい設計
だと言えます。

クラスの仕様部分と利用部分を分けて考えやすくなる

これまで学んできたように、クラスを宣言する部分と、そのクラスを使う部分は分けて考えられます。

  • クラス宣言側
    → 戦士の仕様を作る側
  • main メソッド側
    → その仕様を使ってプログラムを書く側

カプセル化ができていると、仕様を作る側が安全な使い方をあらかじめ用意しておけます。
すると、利用する側は、その使い方に沿ってプログラムを書くだけで、不具合の起きにくいコードを書きやすくなります。

これは実際の開発でもとても重要です。
クラスは、自分だけが使うとは限りません。あとから別の人が使うこともあります。
だからこそ、最初から安全に使える形で公開しておくことが大事なのです。

修飾子を省略するとどうなるのか

ここで少しだけ触れておきたいのが、private や public を省略した場合です。
これらは修飾子と呼ばれます。

何も書かない場合、そのメンバは「同じパッケージの中からアクセスできる」扱いになります。
今の段階では、同じファイルに書かれたクラス同士でアクセスできていたのは、このしくみが関係しています。

ただし、ここではまず

  • private は外から直接アクセスできない
  • public は外から利用できる

という対比をしっかり押さえておけば十分です。

パッケージの詳しい話は、あとで学ぶ内容として置いておいて大丈夫です。

この図では、中央の Saiyan クラスの中が上下に分かれています。
上側には private フィールドがあり、鍵アイコンで守られていることが表されています。これは、内部データを外から直接触れないようにしている状態です。

下側には public メソッドがあり、こちらは開いた扉のアイコンで表されています。
つまり、外から利用してよい入口はここだ、ということです。

左側の Sample2 クラスからは、setStatus(...) や show() へは矢印が通っています。
これは public メソッドなので外から使えることを示しています。
一方、goku.energy = -10.0 は途中で遮られていて、private フィールドへ直接入れないことがわかります。

この図を見ると、「全部を閉じる」のではなく、「危険な直通ルートを閉じて、安全な入口だけを開く」のがカプセル化だと理解しやすくなります。

いちばん大事な感覚

「メソッドを公開して安全に操作するしくみ」で大切なのは、次の感覚です。

  • private でフィールドを守るだけでは、外から必要な設定もできなくなる
  • そこで public メソッドを公開して、安全な操作口を用意する
  • public メソッドの中で値をチェックすれば、不自然な値を防げる
  • private と public を使い分けることで、クラスは安全で使いやすい部品になる
  • データと機能をまとめ、必要なメンバを保護する考え方がカプセル化

ドラゴンボールで言いかえるなら、

  • 戦士の内部状態は勝手にいじらせない
  • でも正式な技や操作手順は公開しておく
  • その技の中で正しい値かを確認してから状態を変える
  • だから、戦士として不自然な状態が生まれにくくなる

ということです。

この感覚がつかめると、クラスはただの設計図ではなく、自分の中身を守りながら、外には安全な使い方だけを見せる部品として見えてきます。ここから先のオブジェクト指向の理解も、ぐっと深まっていきます。