呼ばれるということ

今とあるクライアントさんは足し算がしたいようです。足し算はクライアントさんの責務ではないようです。よって、クライアントさんは足し算の責務を持っているクラスを探して、そのクラスのオブジェクトにメッセージを投げることにしました。

探していたら以下のAddクラスがありました。

Add
package org.kijitoraneko;

public class Add {
    public int addLogEn(int i, int i2){
        System.out.println("start!");
        System.out.println("足します");
        int result = i + i2;
        System.out.println("end!");
        return result;
    }
    
    public int addLogJa(int i, int i2) {
        System.out.println("はじまりです!");
        System.out.println("足します");
        int result = i + i2;
        System.out.println("おわりです!");
        return result;
    }

}
クライアントさんのコード
public class TestCode {

    @Test
    public void testAdd1() {
        Add add = new Add();
        int result = add.addLogJa(5, 5);
        assertThat(10, is(result));
    }
    
    @Test
    public void testAdd2() {
        Add add = new Add();
        int result = add.addLogEn(5, 5);
        assertThat(10, is(result));
    }

}
出力結果
はじまりです!
足します
おわりです!
start!
足します
end!

ここでは、足し算をしたいために足し算のクラスAddに処理を委譲しています(これをメッセージ送信などといったりします)Addクラスの責務は「足し算をすること」です。ここでは抽象レベルの話はしません。場合によってはCalcクラスにするかもしれませんよね(他の計算ロジックも含むなど)。その辺はその時々の設計の問題ですね。


Addクラスにはメソッドの前後にログ出力があります。これはこのクラスの責務ではありませんが、こういう処理はオブジェクト指向では解決できなかったりします。いろいろなパターンのログを出力したい場合には足し算をするという本来の責務はひとつであるにもかかわらず、メソッドがどんどん増えてしまいませんか?


あらかじめログ内容は決まっておらず、使用する側がログの内容をそのつど決定したい場合もあるかもしれません。


あくまでここでは簡単な具体例を出していますが、「このような具体例とは違うこのような状況」はいろいろ考えられるのではと思います。


で、どうしましょうということですが。


こんなんでしょうかね。

ILogBinder
package org.kijitoraneko;

interface ILogBinder {
    void beforeLog();
    void afterLog();
}
AddAop
package org.kijitoraneko;

public class AddAop {
    public int add(ILogBinder calc, int i, int i2) {
        calc.beforeLog();
        System.out.println("足します");
        int result = i + i2;
        calc.afterLog();
        return result;
    }
}
クライアントさんのコード
@Test
    public void testAddAop() {
        AddAop addAop = new AddAop();
        int result = addAop.add(new ILogBinder() {
            @Override
            public void beforeLog() {
                System.out.println("自分でカスタマイズできます スタート!!!!!!!!!!!!!");
            }
            @Override
            public void afterLog() {
                System.out.println("自分でカスタマイズできます END   !!!!!!!!!!!!!");
            }
        }, 5, 5);
        
        assertThat(15, is(result));
    }
出力結果
自分でカスタマイズできます スタート!!!!!!!!!!!!!
足します
自分でカスタマイズできます END   !!!!!!!!!!!!!

この基本を応用すれば、私が出くわした、Connectionのクローズをすべての開発者に課すということもなくなると思います。 というか、Java8のラムダとかではもっと違う感じで書けるのかもしれませんが、私の知識がまだ追いついていません。

その前に、そもそも、ログ処理やトランザクションなどのいわゆる横断的な関心事に関してはAOPフレームワークを使うべきですよね。

結論

「よく調べよう!」