良いコ-ドへの道―普通のプログラマのためのステップアップガイド

第3回 スコープを意識したプログラミング―その4 クラス/パッケージのスコープ

この記事を読むのに必要な時間:およそ 4 分

クラスのスコープ

Javaではクラスのスコープもprivate,package private,protected,publicの4種類です。

クラスの宣言では主にpublicを使用する場合が多いです。

フレームワークやライブラリを作成する場面ではpackage privateを使用することがときどきあります。ライブラリの利用者に知らせたくないクラスをpackage privateとすることで,のちのちクラスを変更しても変更の影響を利用者に与えないようにすることができます。例を見てみましょう。図2はWebアプリケーションフレームワークCubbyのルーティング機能パッケージ(org.seasar.cubby.routing.impl.*)のクラス一覧です。ClassCollectorとInternalForwardInfoImplはライブラリ利用者が知る必要のないクラスですので,package privateで定義されています。この2つのクラスは実際には同じパッケージのPathResolverImplからのみ利用されます。このようにpackage privateを使用することで,クラスのスコープを小さくし,ライブラリやフレームワークが外部に公開するクラスをコントロールすることができます。

図2 Cubbyのルーティングパッケージの構成

図2 Cubbyのルーティングパッケージの構成

privateは,主に2つの目的で使用されます。1つ目は,インスタンスの生成をそのクラスからのみ行わせたい場合です。デザインパターンのシングルトンパターン注1などがこれにあたります。ただしメインのクラス宣言はprivateで宣言できませんので,コンストラクタをprivateで宣言して,他のクラスからはインスタンスの生成をできないようにします。2つ目は,そのクラスからのみ利用するインナークラスの定義です(インナークラスについては次項でも解説します)。GUIアプリケーションのイベントハンドラ定義などがこれにあたります。

protectedは,インナークラスの宣言でのみ使用できます。インナークラスを下位クラスからのみ利用させたいときに利用します。

注1)
本誌Vol.22の特集1「サルでもわかる 逆引きデザインパターン」をご覧ください。この特集はWebでも公開されています

インナークラス

インナークラスとは,クラス内に定義されたクラスのことです。インナークラスはほかのクラスの内部で宣言するものですので,通常はprivateで宣言して問題ないはずです。

なお,staticが付かないインナークラスのメソッドからは,インスタンスメソッド同様にフィールド変数にアクセスできますリスト8)。

リスト8 インアークラス

public class LoginWindow extends Window {
    private int count = 0;
    ...
    public void init() {
        closeButton.addSelectionListener(new CloseButtonSelectionListener());
    }
    ...
    // インナークラスの宣言
    private class CloseButtonSelectionListener extends SelectionAdapter {
        @Override
        public void widgetSelected(SelectionEvent event) {
            // 外側のクラスのフィールドにアクセス可能...
            System.out.println(count); 
        }
    }
}

無名クラス

無名クラスは匿名クラスとも呼ばれます。無名クラスとは,その場でクラス定義を書いて利用するクラス名がないクラスのことです。

無名クラスはそもそも名前が付かないため,宣言した場所でしか利用できません。これはprivateより小さいスコープになります。1ヵ所でしか使用されることがなく将来的にも再利用することがないクラスは無名クラスとして宣言することで,不測の利用を防ぐことができます。ただし可読性の面から,あえて無名クラスを使わずにインナークラスとして宣言するスタイルが好まれる場合もあります。

Javaの無名クラスのメソッドでは,外側のクラスのフィールドや,final宣言されたローカル変数にアクセスできますリスト9)。

RubyのブロックやJavaScriptの無名関数なども,無名クラスと同様に局所的な処理を記述するために利用されます。

リスト9 無名クラス

public class LoginWindow extends Window {
    private int count = 0;
    ...
    public void init() {
        final int result = 10;
        ...
        // 無名クラスの宣言と利用
        closeButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                // 外側のクラスのフィールドにアクセス可能...
                System.out.println(count); 
                // final宣言されたローカル変数にアクセス可能
                System.out.println(result); 
            }
        });
    }
    ...
}

Rubyのブロック(Ruby/Tk)

TkButton.new {
  text "Close"
  command { ... }
}

JavaScriptの無名関数

document.getElementById("closeButton").onclick =
function(event) {
  ...
};

著者プロフィール

縣俊貴(あがたとしたか)

学生時代にMSXで制限された環境でのプログラミングの楽しさを学ぶ。以来,オープンソースのWiki実装「MobWiki」の開発や受託開発などを経て,現在はプロジェクト管理ツール「Backlog」,ドローツール「Cacoo」など,コラボレーション型のWebサービスの企画と製品開発を行う。また,Webアプリケーションフレームワーク「Cubby」のコミッタを務める。福岡在住。株式会社ヌーラボ所属。

ブログ :http://d.hatena.ne.jp/agt

Twitter:@agata

コメント

  • static ではない入れ子クラスは内部クラスではない

    「インナークラスとは,クラス内に定義されたクラスのことです。」とあるが、それは単なる入れ子クラス(nested class:ネストクラス)に過ぎない。
    「インナークラス(inner class)」とはstatic の付かない入れ子クラスのことである。
    仮にも「技術評論社」のサイトで技術情報を掲載するのであれば、ちゃんとチェックすべきである。

    Commented : #2  kariya_mitsuru (2013/03/29, 11:25)

  • トップレベルクラスとネストクラスの説明をしたほうがいいのでは?

    「クラスのスコープもprivate,package private,protected,public」としていますが、それはネストクラスの話ですよね?
    トップレベルのクラスでのスコープは、package privateとpublicであることも説明したほうが、誤解しないように思うのですが、いかがでしょうか。

    Commented : #1  yamadamn (2008/11/12, 11:36)

コメントの記入