Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
56 lines (39 sloc) 4.75 KB
title tags
コマンド指向インターフェイス
API design

http://martinfowler.com/bliki/CommandOrientedInterface.html

モジュールのインターフェイスには、 プロシージャ、またはオブジェクトメソッドを使うのが一般的です。 たとえば契約料の計算をするモジュールが欲しいときには、 BillingServiceクラスを作り、計算をするメソッドを追加します。 そして、そのメソッドを呼び出します。こういうふうに:

aBillingService.calculateCharges(aContract)

一方、コマンド指向インターフェイスでは、 操作毎にコマンドクラスが存在します。 以下のように引数を渡して呼び出します:

CalculateChargeCommand.new(aContract).run()

メソッド指向インターフェイスで使うメソッド毎に、ひとつのコマンドクラスが存在することになるわけです。

コマンドを実行するオブジェクトを別に用意する方法もあります。

aCommandExecutor.run(CalculateChargeCommand.new(aContract))

Strutsなどのフレームワークで使ったことがあるようでしたら、 アクションクラスがこれに相当するとお分かりになると思います。

では、どうして好き/嫌いが分かれてしまうのでしょうか? まず、公平に見て、コマンド指向インターフェイスの方がメソッド指向インターフェイスよりも複雑です。コマンドをインスタンス化し、それから実行する手順を踏まなければなりません。これは単にメソッドを呼び出すよりも複雑です。この手法が好きなひとでも、大きなインターフェイス(サービス層、サーバサイドロジック、主要サブシステムのインターフェイス)にしか適用しないのは、この複雑さが故です。

コマンド指向インターフェイスには多くの利点があります。 まず、コマンド実行クラスをデコレートすることで、コマンドに振る舞いを容易に追加することが出来ます。これはトランザクション操作やロギングなどに使えます。 コマンドクラスはキューを為すことが出来ますし、(コマンドクラスやコマンド内のデータがシリアライズされていれば)ネットワーク経由でやり取りすることも可能です。

コマンドの実行結果は、コマンド名と引数をキーとしてキャッシュしておくこともできます。

よく耳にする不満は、コマンドクラス内のロジックが重複してしまうという問題です。 コマンドクラスがロジックのたくさん含まれたTransaction Scriptsである場合、これはしばしば起こる問題です。コマンド指向だから起こるということではなく、これはTransaction Scriptsの一般的な問題です。if only because many people feel that a class needs a page or two of code to be worthwhile 、適量よりも多くのコードをコマンド内に入れてしまうと、コマンド指向がこれを助長させてしまうかもしれませんが。

ここで「インターフェイス」という言葉を使ってきたことに気付いたかと思います。 コマンドクラスを使うかどうかというのは、 そもそも、クライアントのインターフェイスをどうするかということに関わってきます。 クラス内の実装をどうするかではないのです。 実行メソッドが単一行で、他のメソッドを呼び出すだけというコマンドクラスならば申し分ありません。 こうすることで、コマンド指向の恩恵を十分に受けられます。 ただし、コマンドクラスからはロジックを排除することになります。 こういったコマンドクラスはごく少量のコードしか含まれていません。

コマンドクラスに関してよくある質問は、何が返ってくるのか、です。 ジェネリックな実行メソッドは、ObjectやCommandResultのような一般的な戻り値を必要とします。しかし、もう少し具体的な戻り値が欲しいのではないでしょうか。 命名規則を決めて、コマンドクラス毎に結果クラスを作るという方法があります。たとえば、CalculateChargeCommandからはCalculateChargeResultクラスが返ってくるといったように。または、コマンドクラス内に結果をストアさせるという方法もあります。この場合、コマンドを実行させて、後からオブジェクトに結果を問い合わせるというふうになります。

You can’t perform that action at this time.