デザインパターン プログラミング Java

【TemplateMethodパターン】売上レポートをテキストとHTML形式で出力分けする事例

投稿日:

概要

デザインパターンのTemplateMethodパターンの事例です。
デザインパターンは増補改訂版 Java言語で学ぶデザインパターン入門で学ぶことができますし、Qiitaでも取り上げられています。

ここで紹介するのは、私が自分で適用可能な状況を考えて実装した事例です。
本の写経やブログを読んで終わりではなく、どのような状況でどのように実装できるか?
と自分なりに考えることの重要性は、増補改訂版 Java言語で学ぶデザインパターン入門でも述べられています。

本を読んだり、写経したり、Qiitaを見て真似してみたけど、実際にどうやって使うんだろうか?
という疑問を持っている読者の方に、またオブジェクト指向プログラミングを身に着けたい方の参考になればと思います。

TemplateMethodパターンとは?

説明

ロジックが共通しているが、具体的な処理内容はサブクラスで実装するパターンです。
ロジック部分はスーパークラスで実装されており、ロジック内にある個別の処理内容をサブクラス固有の実装にすることで、ロジックの使いまわしと個別処理の実装を分離することができます。

共通のロジックがコピー&ペーストでいろんな場所に分散すると、修正することも、テストすることも大変になります。
そういった手間をかけないようにするためのパターンです。

クラス図


スーパークラスのSalesReportでoutputメソッドが共通ロジックになっており、その中でtitle、detail、summaryメソッドが実行されるようになっています。
title、detail、summaryメソッドをサブクラスであるTextSalasReportとHtmlSalesReportで個別に実装することで、表示形式を分離しています。

実装

SalesReportクラス

売上レポートのスーパークラス。
・title、detail、summaryの表示形式はサブクラスで定義するため抽象メソッドとしている。
・outputメソッドは共通ロジックであり、変更不可のためfinalとしている。
・summaryAmount、yenメソッドも共通ロジックですが、個別の実装を要求するものではなく、サブクラスで利用できるように提供しているだけです。

TextSalesReportクラス

テキスト形式で売上レポートを出力するクラスです。
出力形式の仕様は以下のようになります。
< yyyy年M月売上レポート >
A社 : 5000000円
B社 : 2500000円
C社 : 500000円
合計 : 8000000円

HtmlSalesReportクラス

HTML形式で売上レポートを出力するクラスです。
出力形式の仕様は以下のようになります。
<h1>yyyy年M月売上レポート</h1>
<table>
<tr><td>A社</td><td>5000000円</td></tr>
<tr><td>B社</td><td>2500000円</td></tr>
<tr><td>C社</td><td>500000円</td></tr>
<tr><td>合計</td><td>8000000円</td></tr>
</table>

SalesRepotMainクラス

売上レポートを表示するためのクラスです。

<出力結果>

サブクラスで実装した仕様の違い

 TextSalesReportクラスHtmlSalesReportクラス
titleメソッドタイトルを<>で囲って表示する。
タイトルの前後に半角スペースを入れること。
タイトルをh1タグで囲って表示する。
detailメソッド会社名と金額をコロンで区切って表示する。
会社名の前と、コロンの前後に半角スペースを入れること。
trタグ内に、tdタグで会社名と金額を表示する。
ただし、最初のtrタグを出力する時だけ、tableタグを追加しておく。
summaryメソッド"合計"と合計金額をコロンで区切って表示する。
"合計"の前と、コロンの前後に半角スペースを入れること。
trタグ内に、tdタグで"合計"と合計金額を表示する。
また、tableの閉じタグを追加しておく。

もし他の出力形式でレポートを出力する場合、ロジックのコピー&ペーストすることなく、別のクラスを追加することで対応できます。
例えば、CSV形式のファイルを出力する必要が出てきたら、CsvSalesReportクラスを作成すればよいということになります。
※サブクラスを追加した結果、スーパークラスに機能追加することが無いという意味では無く、必要に応じてリファクタリングは行われるべきかなとは思っています。

付録(テストコード)

新たなサブクラスの追加でスーパークラスの修正も行った場合、既存のサブクラスに影響を与える可能性があります。
そのためにテストコードを書いておくことはとてもとても重要だと思っています。

リファクタリングでも、既存のコードを修正するのであればテストコードを用意しておくことが望ましいと述べられています。
動いているコードを修正するリスクは高いのです!
テストコードを書けるのであれば、できる限り書くようにしていきましょう。

module-info

Java11の環境であるため、module-infoを利用しています。

TestTextSalesReport

TextSalesReportクラスのテストコードです。
個別に実装するメソッドのテストを行っています。

TestHtmlSalesReport

TestHtmlSalesReportクラスのテストコードです。
TestTextSalesReportと同様に、個別に実装するメソッドのテストを行っています。

テストコードのメリット

実際のところ、この記事を書きあげるまでに何度かコードを書き直しました。
まさしく、リファクタリングを行ったわけです。
その際、テストコードがあったおかげで私は自分の修正に確からしさを感じることができました。

よく「こんな小さな修正でバグが出るはずがない」という思い込みをすることがあります。
(読者のあなたにもあれば、要注意です!)
それでも、ポカはするものなのです。
なので、テストコードがあれば、自分の修正に問題がないことをある程度は保証することはできます。

ですから、何度も言うようですが、テストコードを書けるのであれば、できるだけ書いた方がよいです。
プロジェクト体制やスキルの問題もあると思いますが、私としては自分の仕事に確からしさをもたらし、品質と効率を求めていきたいと思っています。

まとめ

  • 共通ロジックをコピー&ペーストすることなく使いまわすことができるパターンである。
  • 個別の処理内容はサブクラスで自由に実装可能である。
  • 追加のサブクラスが必要になった場合、単純に追加するだけで対応可能である。

参考書籍

増補改訂版 Java言語で学ぶデザインパターン入門

 
最後までお読み頂き、ありがとうございました!
ご意見・ご要望がありましたら、遠慮なくコメント下さい!
もし内容が良かったらランキング評価を頂けると励みになります(^^)

ランキング評価する

-デザインパターン, プログラミング, Java
-, ,

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

【SpringBoot入門】#12~ 削除機能の実装

概要 ダイアログでOK押下された場合の削除処理を実行します。 画面からリクエストされた書籍情報IDをキーに、論理削除を実装します。 システム開発ではほとんどの場合、論理削除を行います。 物理削除するの …

Facadeパターンの使い道をコードとクラス図で説明します。

Facadeパターンはどんな役に立つか? 簡単にいうと、複数の処理のまとめ役。 なので、依頼1つでいろんな仕事をやってくれる点で役に立つ。 Facadeパターンの要件 Facadeクラスはあくまでサブ …

【Spring+Thymeleaf】HTMLの更新をビルドせずに反映させる方法

概要 Spring + Thymeleafの構成において、ビルド無しでHTMLの変更を反映する方法です。 前提 以下の構成で確認したものになります。 ・SpringBoot 2.6.4 ・Thymel …

【Java入門】Supplierの使い方まとめ

概要 Supplierとは供給者という意味です。 その名の通り、引数を取らずに戻り値を受け取ります。   基本的な使い方 Supplier<T> getメソッドによってT型の結果を受け取り …

【Java入門】繰り返し処理(while, for)

概要 繰り返し処理の制御構造について学んでいきましょう。 繰り返しには以下があります。 while(条件に一致する間だけ繰り返す) do-while(一度必ず実行し、その後は条件に一致する間だけ繰り返 …

SpringFramworkの良書

■おすすめ教材
Javaの基本を学んだ人が、次のステップとして読む本(中級者向け)

※SpringはJavaのFrameworkの1つです。
変更のしやすさ、保守性の高さが特徴です。