MJ プログラミング技法の解説

デザインパターンの各問題点を改善するために必要となるテクニックについて説明する。(ここでは MixJuice のコードを使って説明しているが、 Ruby, AspectJ でもコードを書くとよさそう。)

メソッド拡張

既存のクラス中の既存のメソッドを、モジュール継承によってオーバーライドすることができる。

structure-08-07:c01

module original {
  define class C {
    define void m(){...}
  }
}
module extension extends original {
  class C {
    void m(){ original(); ...}
  }
}

スーパーインターフェース追加

既存のクラスに対して、モジュール継承によって新たなスーパーインターフェースを追加することができる。

structure-08-07:c02

module original {
  define class C {...}
  define interface I {...}
}
module extension extends original {
  class C implements I {...}
}

フィールド追加

既存のクラスに対して、モジュール継承によって新たなフィールドを追加できる。

structure-08-07:c03

module original {
  define class C {...}
}
module extension extends original {
  class C {
    int newField;
  }
}

メソッド追加

既存のクラスに対して、モジュール継承によって新たなメソッドを追加できる。

structure-08-07:c04

module original {
  define class C {...}
}
module extension extends original {
  class C {
    define void newMethod(){...}
  }
}

クラス拡張

スーパーインターフェース追加、フィールド追加、メソッド追加をすべて含み得る、既存のクラスの拡張。

アブストラクトメソッド追加

既存のアブストラクトクラスに対して、モジュール継承によって新たなアブストラクトメソッドを追加できる。ただし、すべての具象クラスに対してそのメソッドの実装を別途追加しないと、実行可能なアプリケーションにはならない。

structure-08-07:c05

module original {
  define abstract class S {...}
  define class A extends S {...}
  define class B extends S {...}
}
module extension extends original {
  class S {
    define abstract void newMethod();
  }
  class A {
    void newMethod(){...}
  }
  class B {
    void newMethod(){...}
  }
}

名前空間分離

名前を定義する側は、提供する名前の集合を任意にグループ化できる。名前を利用する側は、グループ化された名前の集合を任意に選んで利用できる。

structure-08-07:c06

module namesA {
  define class A1 {...}
  define class A2 {...}
  ...
}
module namesB {
  define class B1 {...}
  define class B2 {...}
  ...
}
module clientOfA extends namesA { ... }
module clientOfB extends namesB { ... }
module clientOfBothAandB  extends namesA, namesB { ... }

仕様モジュールと実装モジュールの分離

これは名前空間分離の特殊形である。クラス C を、公開仕様を定義するモジュールと、実装を定義するモジュールに分離する。

module c {
  define class C {
    // public methods
    define abstract void m1();
    define abstract void m2();
  }
}
module c.implementation extends c {
  class C {
    // public methods
    void m1(){...}
    void m2(){...}
    // protected fields and methods
    int f1;
    define void m3(){...}
  }
}

実装モジュール選択

あるクラスに対する異なるバージョンの実装を、異なるモジュールで実装しておき、リンク時に実装を選択できるようにしておくことができる。(リンク時には提供されている実装のうち、ちょうど1つの実装モジュールだけをリンクするように注意しなければならない。現在のリンカーの実装では、2つ以上の異なる実装モジュールが指定されてもリンクエラーにはならない。)

structure-08-07:c08

module m {
  define class C {  // NOTE: C is a non-abstract class.
    define abstract void m();
  }
}
module m.implementationA extends m {
  class C {
    void m(){...}
  }
}
module m.implementationB extends m {
  class C {
    void m(){...}
  }
}

MixJuice によるデザインパターン改善カタログ


田中 哲 <akr@m17n.org>, 一杉 裕志 <y-ichisugi@aist.go.jp>