Design Pattern | Proxy Pattern(プロキシパターン)
Proxyパターンとは?
- Proxyという英単語は代理人、代弁者という意味である。
- 既存要素の代わりをする方式である。
- オブジェクト指向では、「自分」も「代理人」もオブジェクトになる。
- Proxyパターンは、忙しくて作業できないオブジェクト自身の代わりに、オブジェクトの代理人が一部の作業をこなす方式である。
- Proxyパターンで重要なのは、フロー制御だけを行い、結果値を操作したり変更したりしてはいけないという点である。
- あるオブジェクトにアクセスするために代理人を使用する。
- GoFのデザインパターンでは、構造に関するデザインパターンに分類される。
Proxyパターンのサンプルプログラム
画面に文字を表示する「名前付きプリンター」のサンプルプログラムである。
Class Diagram

1. Printableインターフェース
PrinterとPrinterProxyの共通インターフェースである。
Printable.java
package com.devkuma.designpattern.structural.proxy;
public interface Printable {
// 名前設定
void setPrinterName(String name);
// 名前返却
String getPrinterName();
// 文字列表示(print out)
void print(String string);
}
2. Printerクラス
名前付きプリンターを表すクラスである。(本人)
Printer.java
package com.devkuma.designpattern.structural.proxy;
public class Printer implements Printable {
private String name;
public Printer() {
heavyJob("Printer의 인스턴스를 생성중");
}
public Printer(String name) {
this.name = name;
heavyJob("Printer의 인스턴스 (" + name + ")를 생성중");
}
public void setPrinterName(String name) {
this.name = name;
}
public String getPrinterName() {
return name;
}
public void print(String string) {
System.out.println("=== " + name + " ===");
System.out.println(string);
}
private void heavyJob(String msg) {
System.out.print(msg);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.print(".");
}
System.out.println("완료");
}
}
3. PrinterProxyクラス
名前付きプリンターを表すクラスである。(代理人)
PrinterProxy.java
package com.devkuma.designpattern.structural.proxy;
public class PrinterProxy implements Printable {
private String name;
private Printer real;
public PrinterProxy() {
}
public PrinterProxy(String name) {
this.name = name;
}
public synchronized void setPrinterName(String name) {
if (real != null) {
real.setPrinterName(name);
}
this.name = name;
}
public String getPrinterName() {
return name;
}
public void print(String string) {
realize();
real.print(string);
}
private synchronized void realize() {
if (real == null) {
real = new Printer(name);
}
}
}
4. Mainクラス
メイン処理を実行するクラスである。
Main.java
package com.devkuma.designpattern.structural.proxy;
public class Main {
public static void main(String[] args) {
Printable p = new PrinterProxy("Alice");
System.out.println("현재 이름은 " + p.getPrinterName() + " 입니다.");
p.setPrinterName("Bob");
System.out.println("현재 이름은 " + p.getPrinterName() + " 입니다.");
p.print("Hello, world.");
}
}
5. 実行結果
현재 이름은 Alice 입니다.
현재 이름은 Bob 입니다.
Printer의 인스턴스 (Bob)를 생성중.....완료
=== Bob ===
Hello, world.
Proxyパターンのメリット
Proxyパターンでは、Proxyが代理人となり、可能な限り処理を肩代わりする。
サンプルプログラムでは、Proxy役を使うことで、実際にprintするまで重い処理(インスタンス生成)を遅延できた。
例えば、初期化に時間がかかる機能が多数存在するシステムの場合、起動時点で利用しない機能まで全部初期化してしまうと、アプリケーションの起動に時間がかかってしまう。
PrinterProxyクラスとPrinterクラスの2つに分けず、Printerクラス内に最初から遅延機能を入れておくこともできるが、クラスを分けることでプログラムの部品化が進み、個別に機能を追加しやすくなる。