「恋するハニカミ!」

出てました,蛯原友里ちゃん\(^o^)/
これってレギュラーって事ですか? 毎週エビちゃん見られるって事ですか? 素晴らしい!
まぁ,まさにお飾りというか添え物というか,そんな感じではあるのですが,それでも全然いいのです.
それにしても友里ちゃん,テレビ写りもよくなってきたというか,雑誌でのイメージと近くなってきた様子.今までテレビでは今ひとつの印象だったので心配していたのですが.今回はちゃんと素敵に見えました.できれば立ち姿も見たいので,エンディングは出演者みんな立って手を振るとかしていただきたい.
先週はせりふなかったらしいですが,今週はちょっとだけ声も聞けました.そうですか,水族館行ったことないのですか.上京してからずっと,CanCamやドラマの撮影で忙しかったのでしょうね.そのうちゲストの代わりに水族館デートなんていいんじゃないでしょうか.いずれ番組卒業なんて時には是非ともお願いしたい.
さぁ,これから毎週見るぞー.*1

*1:と,ここまで書いておきながら,この歳で書く内容じゃないよなーと気づく.心より恥じる.

からさわぎスタイル

id:apiraさんのパクリで(^^; 明日のからさわぎに参加するスタイルを.見かけたZaizenerの方は一声かけてください.一緒に総回診をいたしましょう.

  • インディゴっぽい染めのネイビーのカットソー(Margaret Howel 02-03AW)
  • 明るいラベンダーのパンツ(ISSEY MIYAKE MEN 01SS)
  • 白のスニーカー(JIL SANDER/Puma 02-03AW)

思ったより涼しかった場合はもうちょっと暖かい格好で出かけるかもしれません.心より恥じる.

はてなダイアリー市民:である

今日でちょうど30日になったようです.これでキーワード登録ができる! はず!
日本を代表するインテリア・デザイナーの倉俣史朗さんがキーワードになってないのがとっても気になっていたので,登録しようかな.いろいろ情報調べなきゃ.

Function と Procedure

近頃そこかしこで見かけるホット? それともクール? な話題,return null.それを見ていて同じような話題を思い出したので久しぶりにB.Meyerの名著「オブジェクト指向入門」を開きました.っていうか第2版の翻訳は? 訳者の方,自分の著書は出版しているのに... 「この夏には出ます.」とおっしゃっていたのはもう3,4年も前だというのに... 無念だ.
B.Meyerは同書で,関数(function)と手続き(procedure)は明確に区別するべきだと主張しています.

関数(function)
戻り値がある.
オブジェクトの状態*1は変更しない.
手続き(procedure)
戻り値がない.
オブジェクトの状態を変更する.

まったく逆なんですね.
関数というのは「問合せボタン」です.オブジェクトという機械についている問合せボタンを押すと,機械の状態を知ることができます.しかし,このボタンをいくら押しても機械の状態は変わりません.何度ボタンを押しても,確実に同じ結果を得ることができます.
手続きというのは「変更ボタン」です*2.このボタンを押しても機械の状態は分かりませんが,中ではガチャガチャとなにやら動いているようです.その後で「問合せボタン」を押すと,さっきまでとは違った結果を得ることになります.
原則として正しいのだと思います.特に「オブジェクト指向入門」で紹介されているEiffelというプログラミング言語には,表明という強力な概念が備わっています.表明はオブジェクトの状態やメソッドの引数が正しいことを検証するものですから,状態を変更してはいけません.つまり,関数は利用できますが,手続きを利用してはいけません.この二つを明確に区別することで,ある値を検証するために呼び出したメソッドが思わぬ副作用を持っていたなんていう無用のトラブルを避けることができるわけです.素晴らしい.


確かに素晴らしいのですが,現実はなかなかこの原則を全面的に受け入れられなかったりもします.例えば同書に出てくる乱数の場合.
Javaではこうですが,

Random randomGenerator = new Random();
int rand = randomGenerator.nextInt();

nextInt()は乱数を返すと同時にRandomの状態を変更しています.これは原則に反します.よって,次のようでなくてはなりません.

Random randomGenerator = new Random();
randomGenerator.next();
int rand = randomGenerator.intValue();

うーむ.あなたはこれを受け入れられますか?
同じくスタックの場合.
Javaだとこうですが,

Object item = stack.pop();

pop()はスタックの一番上の要素*3を取り除いて,それを返しています.これは原則に反します.よって,次のようでなくてはなりません.

Object item = stack.top();
stack.pop();

うーむ.うーーーむむ.あなたはこれを受け入れられますか?
さて,この原則と return null を同時に踏みにじっている例として,Map#remove(Object)をあげることができます.このメソッドは,Mapに引数をキーとするマッピングが含まれていればそのマッピングを取り除き,マッピングの値を返します.マッピングが含まれていない場合はnullを返します.

Object item = map.remove(key);
if (item != null) {
    ・・・
}

いけませんねー.次のようでなくてはなりません.

if (map.containsKey(key)) {
    Object value = map.get(key);
    map.remove(key);
    ・・・
}

うーむ.うーーーむむ.うーーーーーーーむむむ.あなたはこれを受け入れられますか?


正しい原則であっても,それを常に押し通すことが適当とは限らない,ということなのでしょう.もちろん,原則を知らないとか無視するのとは訳が違います.正しい原則をよぉく理解して,その上で適当な場合には原則を破ることもいとわない.そんな風にありたいものです.
さて自分は? 原則を知らないことが多いかも... 心より恥じる.

*1:この状態は抽象状態のことで,内部的なキャッシュなど具象状態の変更はありです.

*2:オブジェクト指向入門」では「コマンドボタン」です.

*3:スタックというのは下から上に積み上げるものなのです.

静かな一日

ようやく,よーやく! 静かに一日を過ごすことが出来ました.なにもなし.はぁー,こんなにトラぶったのはじめてだよ.やはり歳は取りたくないものです.心より恥じる.
さ,これで次のお仕事に取りかかれます.今度はガラリと変わって開発環境の整備.現在は VisualAge for Java Enterprise Edition + CVS で開発しているものを,WebSphere Studio Application Developer + ClearCase*1 に変更します.実はアプリケーションサーバ(WebSphere Application Server)は一足先にバージョンアップしていて,VisualAgeが対応しているバージョンとはズレているのです.それどころか,VisualAgeはJDK1.1相当で本番環境はJDK1.3というありさま.なので,早いところこのズレをなくさないといけないわけです.しかーし,9000以上のクラス,10000以上のJSPがあって,並行して開発中の案件も多いときているため,なかなか大変なのです.なにより,あまり楽しい作業ではないのでやる気Nullっぽいところが課題です.

*1:びっくり,キーワードになってるよ!

Spring Framework 入門記 AOPその11 ProxyFactoryBean再訪

順番だと次は「5.4. Advisors in Spring」なのですが,とても短いので軽ーく.Advisorは,Aspectをモジュール化するもので,たいていはAdviceとPointcutを組み合わせたものです.だそうです.直訳風です.以上!
ということで「5.5. Using the ProxyFactoryBean to create AOP proxies」へ進みます.苦しんだ「AOPその1」でこの連載^H^H日記を救ってくれたのがこの5.5節でした.ようやく戻ってきましたよ.
さて,すでに学習したとおり,ProxyFactoryBeanはSpringのAOP機能を実現しているFactoryBeanであり,このAOP編で疑いなく最も重要な存在です.たぶん.
ProxyFactoryBeanもSpringのコンテナから見るとただのBeanですから,プロパティを設定することができます.ProxyFactoryBeanは,次のプロパティを持っています.これまでの学習で,次のプロパティを使用してきました.

target
AspectをWeavingされるBeanを指定します.
interceptorNames
Advice(Interceptor)やAdvisorであるBeanの名前を指定します.

それ以外にも,ProxyFactoryBeanは,次のプロパティを持っています.

proxyTargetClass
booleanのプロパティで,trueにするとinterfaceではなく,classをターゲットにします.これは,java.lang.reflect.Proxyではなく,CGLIBを使ってProxyを作成することを意味します.Proxyをターゲットクラスとして扱うことができます.
java.lang.reflect.Proxyを使用したProxyの場合,それをターゲットクラスとして扱うことはできません(ターゲットクラスのインスタンスではない).interfaceを通してのみ利用できます.
optimize
booleanのプロパティで,trueを設定すると積極的に最適化されたProxyを作成するとのことです.よく分かっていなければ使うなとのこと.僕はいい子なので使わないことにします.無念だ.
frozen
booleanのプロパティで,trueに設定すると,ProxyFactoryBeanが構成された後(コンテナにDependency Injectionされた後)は,ProxyFactoryBeanを変更しないことを意味します.デフォルトはfalseです.
通常は,XMLの定義ファイルに書かれた通りにProxyFactoryBeanを設定した後,プログラマティックに設定を更新するようなことはあまりないと思います.よって,たいていはtrueに設定してもいいのではないかと思います.
exposeProxy
booleanのプロパティで,trueに設定すると,ProxyをThreadLocalから取得できるようになるとのこと.そのThreadLocalは,AopContextから取得できるそうです.って「5.5. Using the ProxyFactoryBean to create AOP proxies」には書いてあるのですが,現実にはAopContext#currentProxy()で取得するのかな? このドキュメント,結構実装と食い違っている記述が多いんで,油断大敵です.
それで,AopContextは抽象クラスなのですが,そのインスタンスはどこから入手できるのでしょう? うーん,もっと先に出てくるのかな? とりあえず保留.無念だ.
aopProxyFactory
ProxyFactoryBeanが使用するProxyのファクトリであるProxyFactoryを設定します.これを切り替えることで,まったく異なったAOP Proxyを使用できるようになるというわけです.ふーん.あまり必要になって欲しくない感じですが,万が一の時にはいろいろ好きなようにできるということですね.
proxyInterfaces
Classの配列のプロパティで,Proxyが実装するinterfaceを指定します.このプロパティが設定されない場合は,CGLIBを使用してターゲットの派生クラスとしてProxyが作成されます.
このプロパティが設定されると,java.lang.reflect.Proxyを使用したDynamic Proxyが作成されます.
singleton
FactoryBeanおなじみのbooleanのプロパティです.
falseに設定されると,コンテナからインスタンスを取得するたびに新たなProxyが作成されます.ステートフルにmixinを組み込む場合に使えるとか.でもそれってどんな場合?

ソースを見ると他にもプロパティらしきものがあるようなのですが,ドキュメントに登場するのは以上です.
これまでの学習では,proxyInterfaceを指定したことがなく,常にCGLIBによるProxyを使ってきたので,これを試してみることにしましょう*1
まずはinterfaceを用意します.

package study;

public interface Foo {
    void print();
}

その実装クラスを作成します.

package study;

public class FooImpl implements Foo {
    private String text;
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public void print() {
        System.out.println(text);
    }
}

そして定義ファイル.<bean>要素以下のみです.

<bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target">
        <bean class="study.FooImpl">
            <property name="text"><value>FOO</value></property>
        </bean>
    </property>
    <property name="proxyInterfaces"><list><value>study.Foo</value></list></property>
    <property name="interceptorNames"><value>debugInterceptor</value></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>

ごらんのとおり,proxyInterfacesプロパティにFooを指定しています.
そして実行用のクラスです.中ほどのみ.

Foo foo = (Foo) context.getBean("foo");
foo.print();
FooImpl fooImpl = (FooImpl) foo;

まずはinterfaceで取り出して,print()メソッドを呼び出しています.その後,FooImplにキャストしています.
さぁ,実行!!

Debug interceptor: count=1 invocation=[Invocation: method=[public abstract void study.Foo.print()] args=null] target is of class study.FooImpl]
FOO
Debug interceptor: next returned
java.lang.ClassCastException
    at study.Main.main(Main.java:16)

というわけで,ちゃんとAspectが適用されていること,Fooというinterfaceでは扱えるものの,FooImplというターゲット本来のclassとしては扱えないことが分かります.
なお,proxyInterfacesプロパティを指定していても,proxyTargetClassプロパティにtrueを設定すると,FooImplにキャストすることが出来ました.CGLIBによるProxyが作成されるからですね.
なお,CGLIBを使ったProxyの場合,ターゲットでfinal宣言されているメソッドにはAspectを適用できないそうです.なるほど.こういった点を踏まえて,両者を使い分けようということですね.この入門記のようなお遊びではともかく,実際の開発で使うなら,きっちりinterfaceを定義してやりたいところです.その場合はjava.lang.reflect.Proxyを使うことができるので,その方がよさそうな気がします.
ということで,全然たいした事をしていませんが,今日はここまで.次は「5.6. Convenient proxy creation」に進みます.

*1:いやその,ひがさんの日記で指摘されていた「デフォルトコンストラクタがないとAspectを適用できない」を確認したときに,こっそり試したことがあるんですが,日記としてはやっていないので... 心より恥じる.