読者です 読者をやめる 読者になる 読者になる

新人SEの学習記録

14年度入社SEの学習記録用に始めたブログです。気づけば社会人3年目に突入。

学習記録:デザインパターン

[学習記録] デザインパターン

内容 第21章:Proxyパターン

また少し飛ばして21章から。

概要
  • 代理人を立てる
    • 本人でなくてもできるような仕事をまかせる
    • 代理人ができる範囲外の仕事は、代理人から本人にやってもらう
サンプルプログラム
Writer 画面に文字を出力するクラス
WriterProxy 画面に文字を出力するクラスの代理人
Main 動作確認用
  • Writerクラス
    • 画面に文字を出力するクラス。名前のフィールドを持つ。
    • setWriterNameメソッドで名前を変更し、printメソッドで名前と文字を出力する。
public class Writer {
    private String name;
    public Writer(String name) {
        this.name = name;
    }
    public void setWriterName(String name) {
        this.name = name;
    }

    public String getWriterName(String name) {
        return name;
    }

    public void print(String str) {
        System.out.println("[" + name + "]: " + str);
    }
}
  • WriterProxyクラス
    • Writerクラスの代理人。名前と本人(Writerクラス)のフィールドを持つ。
    • Writerクラスと同じメソッドを持つが、printメソッドではWriterクラスのprintメソッドを呼び出す。
    • printメソッドが呼び出されたとき(=本人であるWriterクラスが必要なとき)に初めてWriterクラスを生成する。
    • 逆に、nameを変更/取得する際にはWriterクラスは生成されない。
    • また、setWriterNameメソッドを呼び出した回数をカウントしている。
public class WriterProxy {
    private String name;
    private int setNameCount;
    private Writer real;
    public WriterProxy(String name) {
        this.name = name;
        this.setNameCount = 0;
    }
    public synchronized void setWriterName(String name) {
        if (real != null) {
            real.setWriterName(name);
        }
        this.name = name;
        setNameCount++;
    }

    public String getWriterName(String name) {
        return name;
    }
    public void print(String str) {
        realize();
        real.print(str);
    }
    public int getCount() {
        return setNameCount;
    }
    private synchronized void realize() {
        if (real == null) {
            real = new Writer(name);
        }
    }
}
  • Mainクラス
    • 代理人であるWriterProxyを生成し、名前を変更してprintする。
    • また、名前の変更回数を取得する。
public class Main {

    public static void main(String[] args) {
        WriterProxy wp = new WriterProxy("Foo");
        wp.setWriterName("Bar");
        wp.setWriterName("Hoge");
        wp.print("Hello, World!");
        System.out.println(wp.getCount());
    }
}
[Hoge]: Hello, World!
2
補足
  • 代理人を使うメリット
    • Writerクラスのインスタンス生成が非常に時間の掛かる処理の場合
    • Proxyを使うことで、重い処理を実際にprintを行うときまで遅らせることができる
    • また、本人役のクラスには無い機能を、本人役のクラスには手を加えずに追加できる(getCountメソッド
    • 機能を利用したくないときは、Proxyクラスを使わなければ良い(本人を使用すれば良い)
  • Proxyのパターン
    • Virtual Proxy:本章で紹介したProxyパターン。本当に本人が必要になった時点で生成・初期化を行う。
    • Remote Proxy:本人がネットワークの向こう側にいるにもかかわらず、こちら側にいるかのようにメソッド呼び出しができるもの。
    • Access Proxy:本人役の機能に対してアクセス制限を設けるもの。権限のあるユーザからはメソッド呼び出しを許可するなど。