送料、合計金額はJSONで実装
ただ単に合計金額を求めるのであれば、BasketImplの情報から求めることができます。しかし、現実のネットショップでは一定額以上の買い物をすると送料が無料になったりします。このような計算は買い物かごの責務ではありません。次回ではタイムセールスの機能を入れ、ある時間帯になると割り引くサービスを入れる予定です。これらをBasketImplの実装に含めてしまうと、変更が容易ではありません。従って、ここでCalcChargeというサービスを作成し、送料、合計金額の計算を行うようにします。
では、今回は第3回で説明した仕様に「買い物の合計金額が15,000円以上の場合、送料は無料とする」という要求を追加します。
皆さんもお気づきと思いますが、送料や合計金額の計算はREST向きではありません。ただし、計算の基となる情報はBaskeImplが保持しているため、このクラスにTotalというインターフェースを追加します。それを実現するBasketImplクラスのgetTotalメソッドからCalcChargeを呼び出すという方法がスマートだと言えます。従って、BasketImplクラスには2つのインターフェースが存在し、2つのインターフェースのバインディングはAtomとJSONとなります。図12がTotalインターフェースです。図13がBasketImplのgetTotalメソッドです。図14がCalcChargeインターフェースで、図15がCalcChargeImplクラスです。コンポジットの外部に公開しないサービスでは、インターフェースで@Remotableアノテーションは不要です。しかもCalcChargeImplクラスはCalcChargeインターフェースの実装すらしていません。
ただし、CalcChargeインターフェースに@Remotableアノテーションを付けることも可能です。再利用する可能性が高いコンポーネントの場合、@Remotableを付けることをおすすめします。次回ではBasketとCalcChargeコンポーネントをWebサービスでワイヤリングするため、インターフェースには@Remotableアノテーションを付け、CalcChargeImplクラスはCalcChargeインターフェースを実装します。



すべてを組み合わせる
これで、ワインリスト、買い物かごが完成しました。後はこれらを組み合わせるだけです。第3回でも説明しましたが、組み合わせるためにはコンポジットファイルというXMLファイルに記述するだけです。設定ファイルなどのXMLファイルは理解が難しいものが多いですが、コンポジットファイルは直感的で非常に分かりやすいです。図16がコンポジットファイルです。前回と比べ、BasketコンポーネントとCalcChargeコンポーネントが増えています。Basketコンポーネントには2つのサービスが存在します。従って、WineShopコンポーネントも2つのリファレンスが増えています。リファレンスのtarget属性は参照しているコンポーネントのname属性値とサービスのname属性値を「/」で連結しています。ネーミングとしては、あまりよくないですが、コンポーネントとサービスの属性が同じであってもエラーとはなりません。興味深い例として挙げましたが、実際には最低でもコンポジット内ではユニークになるよう命名すべきです。
先述したCalcChargeImplクラスがCalcChargeインターフェースを実装していなくても、エラーとならなかったのは、コンポジットファイルで実装しているクラスを指定できるためです。これは非常に重要なことで、実装を仕様として持たない言語の場合でも、コンポジットファイルで実装クラスを指定できるため、実装言語の範囲が広がります。将来的には多くの言語がサポートされることを願っています。
プロジェクトの全体構成は図17のようになります。

今回は、買い物かごを作成し、商品の「検索」「登録」「変更」「削除」機能や、合計金額や送料を算出する機能の実装方法について説明しました。次回は、CalcChargeコンポーネントをWebサービスでワイヤリングする方法を説明します。


