Java:フレームワークの自作

ここでは、抽象クラスとリフレクションの二通りの方法で超簡易フレームワークを作成する方法を紹介します。
家で例えるなら、フレームワークは骨組みの部分です。言い換えると、共通部分です。同じ骨組みでも内装や外装の異なる家を複数建てたい場合がありますよね。 そういう場合は、あらかじめ共通の骨組みを作っておいて、内装や外装を後からカスタマイズできるようにしておくと便利です。 フレームワークには、更に、発生したイベントに応じて、ユーザが登録した関数(コールバック関数)を呼び出すイベント駆動の機構が備わっています。
下記の例では、Frameworkクラスが骨組みで、Modelクラスが内装や外装に相当します。MVCモデルで言えば、Frameworkクラスがコントローラで、Modelクラスがモデル、標準入出力がビューに相当します。


ライブラリとフレームワークの違い
ライブラリでは、ユーザ定義関数(user-defined function)がライブラリを呼び出すのに対し、 フレームワークでは、イベントが発生したときにフレームワークがユーザ定義関数を呼び出します。


1.抽象クラスを使ったフレームワーク

抽象クラスを使ったフレームワークはオーソドックスな方法ですが、弱点は、メソッド名やメソッド数がフレームワーク側で決まり、ユーザ側ではそれらを決定できないことです。 HttpServlet は抽象クラスを使って作られています。

 

D:\pkg\framework\Framework.java

package framework;

import java.util.Scanner;

public abstract class Framework {
  protected Framework() {
    Scanner scanner = new Scanner(System.in);
    while (true) {
      String event = scanner.nextLine();
      switch (event) {
        case "event1":
        handle1();
        break;

        case "event2":
        handle2();
        break;

        case "event3":
        handle3();
        break;

        default:
        System.err.println("exception");
      }
    }
  }

  protected abstract void handle1();
  protected abstract void handle2();
  protected abstract void handle3();
}
 

 

Frameworkクラスのコンパイル

D:\pkg\javac0.bat(ファイル名をjavac.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
javac D:/pkg/framework/*.java
 

 

次にユーザ側のプログラムです。Frameworkクラスを継承し、コールバック関数 handle1、handle2、handle3 を実装(登録)して Modelクラスを完成させます。

 

D:\src\model.java

import framework.Framework;

class Model extends Framework {
  protected void handle1() {
    System.out.println("action1");
  }

  protected void handle2() {
    System.out.println("action2");
  }

  protected void handle3() {
    System.out.println("action3");
  }
}
 

 

D:\src\main.java

class Main {
  public static void main(String... args) {
    new Model();
  }
}
 

 

ModelクラスとMainクラスのコンパイル

D:\src\javac0.bat(ファイル名をjavac.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
javac -cp D:/pkg *.java
 

 

Mainクラスの起動

D:\src\java0.bat(ファイル名をjava.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
java -cp .;D:/pkg Main
 



〈実行〉

event1[Enter]
action1
event2[Enter]
action2
event3[Enter]
action3


2.リフレクションを使ったフレームワーク

Javaのリフレクションは、実行時に、文字列(変数名や関数名)を通して、変数の読み書きや関数の呼び出しを行うための機能です。 この機能を使うと、switch文を使わずに、登録したメソッドをメソッド名(文字列)で呼び出すことができます。 リフレクションでフレームワークを作成すると、ユーザ側でメソッド名やメソッド数を自由に決めることができます。 Apache Struts はリフレクションを使って作られています。

 

D:\pkg\framework\Framework.java

package framework;

import java.lang.reflect.Method;
import java.util.Scanner;

public class Framework {
  public Framework() {
    Scanner scanner = new Scanner(System.in);
    while (true) {
      try {
        String event = scanner.nextLine();
        String stringClass = event.split(":", 0)[0];
        String stringMethod = event.split(":", 0)[1];
        Class<?> clazz = Class.forName(stringClass);
        Method method = clazz.getMethod(stringMethod);
        method.invoke(clazz.newInstance());
      }
      catch (ReflectiveOperationException e) {
        e.printStackTrace();
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
 


注)catch (Exception e) {} を外すと、捕捉できない例外が発生したときにループを抜けてしまいます。

次にユーザ側のプログラムです。メソッド名はユーザ側で自由に決めることができます。

 

D:\src\Model.java

public class Model {
  public void handle1() {
    System.out.println("action1");
  }

  public void handle2() {
    System.out.println("action2");
  }

  public void handle3() {
    System.out.println("action3");
  }
}
 

 

D:\src\main.java

import framework.Framework;

class Main {
  public static void main(String... args) {
    new Framework();
  }
}
 



コンパイルや実行は、抽象クラスの場合と同じです。


〈実行〉

Model:handle1[Enter]
action1
Model:handle2[Enter]
action2
Model:handle3[Enter]
action3


参考サイト