デザインパターン プログラミング 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


関連記事

【JUnit5】テストコードの基本

概要 JUnit5でテストコードを書く基本について学ぶ。 テストの命名規則 テストクラス、テストメソッドの記述には一般的な慣例があります。 ここではそれらを紹介しますが、実際にはプロジェクト内でのコー …

Redmineでリンクにできない場合にチェックすること

リンクにできない場合のチェック項目 前後に文字列がくっついている。 前後に全角スペースがある。 リンクの#が全角になっている。   リンクにするには? 以下のルールで記述すればリンクにできま …

【Java】オブジェクト指向の練習題材(会計オブジェクト)

前回記事、オブジェクト指向とは何なのかを簡単に説明してみるの練習題材です。 ここでは3つのオブジェクトを作成していきます。 – 会計オブジェクト:会計金額の算出 – 請求書オブ …

【SpringBoot入門】#4~ headerの作成と埋め込み

概要 全ての画面で使用するヘッダーを作成します。 そして、Index画面に埋め込むところまでを行います。 共通ヘッダーの作成

・&lt …

【JdbcTemplate】Queryの書き方(更新系)

  前提 以下のテーブル(users)を持ち、格納するのはUserクラスという想定で説明していきます。 usersテーブル

記事を探す

SpringFramworkの良書

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

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