Skip to content.

Sections
Personal tools

Cotton Bolls: January 2004 Archives

Document Actions

« December 2003 | トップページ | February 2004 »

2004.01.25

アスペクト指向のデザインパターン的解釈

先日AspectJ in Actionという本を読み終えた.AspectJを実際に仕事で使ったことはないが,こういう新しい機能を見ていると昔C++でtemplateや多重継承で悩んでいたことを思い出す.仕組みも理解できるし,かなり強力なツールであることもわかる.しかし,どう使えばいいかわからないのだ.そのためどうしても負の面だけが見えて懐疑的・保守的になってしまう.

templateと多重継承の場合は,そういった疑念を一気に打ち払うキラーアプリがあった.STLとMix-inアーキテクチャだ.どちらもtemplateと多重継承の見方を180度変えるすばらしいものだった.アスペクト指向にもそういう目の覚めるようなものが一つ出てくればいいなと思う.もちろん,AspectJ in Actionにも有用な例はたくさん出ている.しかし,180度見方を変える…とまでは行かない.とはいえ,これからもっと面白いものが出てきそうな気配は十分にあった.

アスペクト指向は,GoFのMediatorパターンに似ているような気がする.正確には,ObserverパターンとMediatorパターンの合わせ技というべきか.

Mediatorパターンでは,いろいろなオブジェクトの相互作用をひとつのクラスにまとめてプログラムを簡潔にする.この一極集中のやり方はアスペクト指向のAspectに相当しているといえるだろう.

また,MediatorクラスはObserverパターンを使って各オブジェクトのイベントをフックすることが多い.イベントが起こったとき,他のオブジェクトに指示を与えて相互作用させるわけだ.イベントをフックする部分はpointcut,相互作用させるコードはadviceに相当しているといえるだろう.

もちろん,Mediatorとアスペクト指向は異なる部分も多い.まず適用される規模が全然違う.Mediatorパターンならダイアログにあるウィジェットを管理するので精一杯だろうが,アスペクト指向ならシステム全体に影響を与えることも簡単だ.

また,pointcutは静的に宣言されるのに対し,Observerパターンによるイベントのフックは動的に行われる.この部分だけはMediatorのほうに分があるかもしれない(注:AspectJしか知らないので間違っているかも.他の実装なら動的に決められるのかもしれない).

結局何が言いたかったかというと,アスペクト指向の適用するとき,これをシステム規模のMediatorパターンとみなせば何かヒントが見えるかもしれない,ということだ.本当はCross Cutting Concernが基本だろうが,オブジェクト指向に慣れた人ならMediatorパターンのほうが考えやすいかな,と思った.

10:37 PM in AOP | 固定リンク | コメント (0) | トラックバック

2004.01.18

Type Safe Enumパターンの謎のクラス

Type Safe Enumパターンで最近ハマった.下のクラスをコンパイルすると,なぜかOuter$1.classという謎のクラスファイルができてしまう.

public class Outer {
    public class Enum {
        private Enum() {}
    }
    public Enum ONE = new Enum();
    public Enum TWO = new Enum();
    public Enum THREE = new Enum();
}

無名クラスを使ってないのに,どうしてOuter$1.classができるのか不思議だった.jadで解析するとjavacが次のように解釈していることがわかる.

public class Outer
{
    static class ??? {}
    public class Enum {
        private Enum() {}
        Enum(??? o) { this(); }
    }
    public Outer()
    {
        ONE = new Enum(null);
        TWO = new Enum(null);
        TREE = new Enum(null);
    }
    public Enum ONE;
    public Enum TWO;
    public Enum THREE;
}

ここでOuter$1クラスを???とした.つまり,Outer.Enumクラスのコンストラクタはprivateなので,外のクラスOuterがアクセスするために別のコンストラクタが作られ,このOuter$1クラスはシグニチャを一意にするために用意された無名クラスということだろう.試しにOuter.Enumクラスのコンストラクタからprivateをとると無名クラスは生成されなかった.

public class Outer {
    public class Enum {
        Enum() {}
    }
    public Enum ONE = new Enum();
    ...
}

なぜこんなことで悩んでいたかというと,EclipseのコンパイラではOuter$1.classが生成されず,SunのSDKでは生成されていたからだった.EclipseのコンパイラはJDKと違うclassファイルを吐くらしい.ビルドの方法を移行中に余計なクラスファイルができていることに気付いたため,しょうもないことで一日悩んでしまった.またバッドノウハウが増えてしまったなあ.

08:07 PM in Java | 固定リンク | コメント (0) | トラックバック

2004.01.14

期待値のデータ構造の作成

Converterライブラリを使っていると,期待値としてオブジェクトのツリー構造などがほしいときがある.例えば

  root
   ├ sub1
   │ ├ sub1-1
   │ └ sub1-2
   ├ sub2
   │ └ sub2-1
   │    └ sub2-1-1
   └ sub3

というのが期待値だとすると,PropertyクラスとObject配列で次のように書かなければならない.

  expected = new Property("root", new Object[] {
      new Property("sub1", new Object[] {
          "sub1-1", "sub1-2",
      }),
      new Property("sub2", new Object[] {
          new Property("sub2-1", new Object[] {
              "sub2-1-1"
          }),
      }),
      "sub3",
  });
  converter.assertEquals(expected, actual);

これだけでも非常に複雑なので,XMLやYAMLで簡単に書けないか考えた.XML版はこんな感じだろうか(p: Property, o:Objectとした)

  <?xml version="1.0"?>
  <!DOCTYPE expected SYSTEM "expected.dtd">
  <expected>
    <p name="root">
      <p name="sub1">
        <o value="sub1-1"/>
        <o value="sub1-2"/>
      </p>
      <p name="sub2">
        <p name="sub2-1">
          <o value="sub2-1-1"/>
        </p>
      </p>
      <o value="sub3"/>
    </p>
  </expected>
 

一方YAML版はこんな感じだろうか.

  --- 
  root: 
    - 
      sub1: 
        - sub1-1
        - sub1-2
    - 
      sub2: 
        - 
          sub2-1: sub2-1-1
    - sub3

これでもかなり冗長な気がする.テストコード中に埋め込むとなると改行\nを書くのも面倒だ.結局,次のようなPropertyTreeクラスを作ることにした.

  PropertyTree pt = new PropertyTree();
  pt.add("root");
  pt.add("  sub1");
  pt.add("    sub1-1");
  pt.add("    sub1-2");
  pt.add("  sub2");
  pt.add("    sub2-1");
  pt.add("      sub2-1-1");
  pt.add("  sub3");
  converter.assertEquals(pt.eval(), actual);

次回のConverterライブラリのバージョンアップに含めようかと思う.そういえば,JMockで使われている方法も試してみたのだった.すごい短い名前のファクトリクラスを使うという方法だ.それを応用するとこんな感じになるだろうか.

  expected = 
    E.p("root" 
        E.p("sub1",
            "sub1-1",
            "sub1-2"),
        E.p("sub2",
            E.p("sub2-1", "sub2-1-1"))
        "sub3");

かなりすっきりするが,(少なくとも1.4までの)javaは可変長引数が使えないためやめてしまった.子供が5個以上ならnew Object[]に切り替える,というのがいやだったためだ.

12:28 PM in JUnit | 固定リンク | コメント (0) | トラックバック

2004.01.02

Name and Conquer

オブジェクト倶楽部のメーリングリストに平鍋さんがソフトウェア原則の連載記事を書いている.

http://objectclub.esm.co.jp/ml-arch/magazine/24.html

これによると,数学の問題を解く方法は大きく2つの方法に分けられるそうだ.

  1. Divide and Conquer
  2. Name and Conquer

Divide and Conquerは,分割統治法としてよく知られるものだ.プログラミングで初めてこのことに気付かせてくれたのは,結城浩さんの「C言語プログラミングのエッセンス」だったように思う.繰り返しの意義について,結城さんはこう書いている.

大きくて難しい問題を,小さくて易しい問題の繰り返しとしてとらえよ.

プログラミングが難しくてわからなくなったときは,いつもこの言葉を思い出すようにしている.

後者のName and Conquerは平鍋さんの記事を読むまで知らなかった.オブジェクト指向は名前が大切だとずっと思っていたが,それを表す言葉として非常にいいなと思った.

名前の重要性は,大学時代に学んだ数学で実感した.関数論は,複素数上で定義された関数を扱う数学の一分野だが,「正則」という概念を導入することで非常に綺麗な理論が展開できる.そのとき「正則」を考えたコーシーはやっぱり天才だと思った.

数学やソフトウェア以外にも,十二国記という小説で名前に関する面白い記述を見つけた.ちょっと引用してみよう(小野不由美著「十二国記 風の海 迷宮の岸(上)」より).

「使令を繋ぎ,守る鎖が『名前』です。麒麟は気迫でもって妖魔を引きだし、相手の名を読みとり、その名をあらためて与えて己の僕とする。妖魔は気迫でもって麒麟の力を測り、名を受けて将来死体を得る権利を手に入れる。――折伏とはそういうことです」

この小説では,麒麟は最高級の神獣として登場する.麒麟は,妖魔を使令としてもつことができるのだが,妖魔を使令にすることを折伏(しゃくぶく)といい,そこで名前が重要な役割として出てくる.文章を書く人も名前に関しては敏感で,いつも深く考えているのかもしれない.

11:00 AM | 固定リンク | コメント (0) | トラックバック

謹賀新年

あけましておめでとうございます.今のところ試験的に書いてますが,長続きしそうなら公開してもいいかな.とりあえず,書いていく分野はソフトウェア開発にしぼってみます.

10:04 AM | 固定リンク | コメント (0) | トラックバック