リスコフの置換原則とは

リスコフの置換原則とはオブジェクト指向の設計の原則の一つであり、「基本クラスをサブクラスに入れ替えても問題なく動かなけらばならない」という原則です。
もしサブクラスに入れ替えると正しく動かなくなるのであれば、クラスを利用する側はサブクラスを使用してはならないというのを意識しながらコーディングしなければならず、保守性が低下します。

クラスの入力・出力に目を向けると、以下の条件を満たすとリスコフの置換原則を満たすことができます。

1.サブクラスの入力のパターンは、基本クラスの入力のパターンよりも緩い

2.サブクラスの出力のパターンは、基本クラスの入力のパターンよりも厳しい
 

もし、サブクラスの入力のパターンが基本クラスの入力のパターンよりも厳しいと、利用する側はサブクラスを利用する際にサブクラスが許容する入力であるかどうかを意識する必要が出てきてしまいます。
また、サブクラスの出力のパターンが基本クラスの出力のパターンよりも緩いと、利用する側はサブクラスを利用する際にサブクラスが予期せぬ出力をしないか意識する必要が出てきてしまいます。

以下のサンプルコードは、割り算を行う基本クラスであるDivideクラスを、サブクラスのDivideBusinessクラス・DivideBad1クラス・DivideBad2クラスで入れ替えてみるサンプルです。

DivideBusinessクラスは、基本クラスが許容する入力パターンに加え分母=0のパターンも許容し、基本クラスが出力することがある負数を出力しません。Divideクラスと入れ替えても特に考慮するパターンが増えることはなく、リスコフの置換原則を満たした良いクラスです。
しかし、DivideBad1クラスは、基本クラスが許容する分子=負数のパターンを許容せず、基本クラスと入れ替えた場合は分子が負数になっていないか意識する必要が出てきてしまいます。
また、DivideBad2クラスは、基本クラスと異なりnullを出力するパターンがあり、基本クラスと入れ替えた場合は出力がnullになる場合を意識する必要が出てきてしまいます。

【サンプルコード】

・DivideMain.java

・Divide.java

・DivideBusiness.java

・DivideBad1.java

・DivideBad2.java

【結果】


いかがでしたでしょうか。

ポリモーフィズムを利用するとソースコードを簡潔にできるのですが、それを実現するためにはリスコフの置換原則を満たすことが必要です。
デザインパターン等で良い設計に触れている方なら自然に満たせるものかもしれませんが、今一度意識してみるのも良いかもしれません。

単一責任の原則とは

オブジェクト指向の設計ではいくつかの原則があります。
その中でも有名な原則の一つが「単一責任の原則」です。

この原則は、その名の通り「一つのクラスに持たせる責任は一つにする」という原則です。
この原則が何のために用いられるのかと言うと、複数の理由で1つのクラスを修正するのを防ぐためです。
ここで言う「理由」を「案件」、「クラス」を「ソース」と捉えると分かりやすいと思います。
複数の案件で1つのソースを修正する必要が出てしまうと、並行開発手順やバージョン管理等が煩雑になってしまい、品質に悪影響が及びます。

「一つのクラスに持たせる責任は一つにする」と捉えると具体的なイメージが浮かびにくいと思うのですが、「複数の案件で1つのソースを修正しないような粒度で設計する」と捉えると分かりやすいと思います。


以下では、javaのソースコードで例を出します。
商品の名前と値段を登録し、それを表示するという例です。

まずは悪い例からです。

【サンプルコード1】

・CommodityMain.java

・RegistShowCommodity.java

【実行結果1】


ここで、「商品の税込み価格を計算可能にする」という案件と、「表示を綺麗にする」という案件が発生したとします。
今の設計だと、どちらの案件も RegistShowCommodityクラスの修正となってしまいます。

そこで、商品の登録を行う RegistCommodityクラス、商品の価格計算を行う CalcCommodityクラス、価格表示を行う ShowCommodityクラスの3クラスに分割します。

【サンプルコード2】

・CommodityMain.java

・RegistCommodity.java

・CalcCommodity.java

・ShowCommodity.java

【実行結果2】


3クラスに分割した結果、「商品の税込み価格を計算可能にする」という案件は CalcCommodityクラスの修正、「表示を綺麗にする」という案件は ShowCommodityクラスの修正で対応できるようになり、別々の案件で1つのクラスを修正する状態を防ぐことができました。

【サンプルコード3】

・CommodityMain.java

・RegistCommodity.java

・CalcCommodity.java

・ShowCommodity.java

【実行結果3】


いかがでしたでしょうか。

オブジェクト指向の設計と言うと覚えることが多くて大変だという印象を持つかもしれませんが、いくつかの原則を抑えるだけでも良い設計ができます。
(デザインパターンも、原則に則って設計を考えると自ずと導き出されるものだと思っています)

単一責任の原則は代表的な原則の一つなので、覚えておいて損はないと思います。

WindowsPowerShellでHelloWorld

WindowsPowerShellとは、Windows7以降に標準搭載されているスクリプト言語です。
比較的新しい言語であり、従来のWindowsバッチ(cmd.exe)に慣れていると取っつきにくい面もあるのですが、後発である分高機能であり、実務でも使うことがあります。

今回は、WindowsPowerShellの簡単な説明を添えながらHelloWorldを3つ試してみます。


1つ目は、echoコマンドを用いたHelloWorldです。
WindowsPowerShellでは、従来のWindowsバッチやLinuxのBashシェルに近い感覚で処理を書くことができます。
他には、変数やif文やパイプといった、お馴染みの書き方が可能です。
ちなみに、少し変わった所では、例外処理をtry-catchやthrowといった書き方で記述することも可能です(こちらはjavaやC#に近いです)。

なお、WindowsPowerShellは、セキュリティ上の関係で、標準設定では直接実行することができません。
設定を変えずに実行するためには、一時的にポリシーを変更して実行する必要があります。
(今回の例では、Windowsバッチを介して実行します)

【サンプルコード】

・Hello.ps1

・Hello.bat

【実行結果】


2つ目は、コマンドレットを用いたHelloWorldです。
コマンドレットは、「動詞-名詞(-パラメータ名 パラメータ値)」という規則で命令を記述します。

今回は、”Write-Host”を使用します。
“Write”は文字列の書き込み、”Host”はコンソールを意味します。
(なお、WindowsPowerShellでは、コンソールへの出力とストリーム(パイプ)への出力は別々に制御します。ストリームに出力したい場合は、”Host”の代わりに”Output”を指定します。)

【サンプルコード】

・Hello.ps1

※Hello.batは変更無し

【実行結果】


3つ目は、.NetFrameworkの機能を使用したHelloWorldです。
WindowsPowerShellでは、.NetFrameworkの機能を使用することもできます。
例えば、”Hello World!!”と書かれたポップアップを表示することができます。

今回の例では、コマンドレットでWindowsFormを取り込み、MessageBoxクラスのShowメソッドを使用してポップアップを表示します。
記述方法はサンプルコードの通りですが、クラス名とメソッド名の記述方法はC++に似ています。

【サンプルコード】

・Hello.ps1

※Hello.batは変更無し

【実行結果】


いかがでしたでしょうか。

Windows7の前の時代からIT業界に居た方にとっては、WindowsPowerShellはもしかしたら馴染みが薄いかもしれません。
また、標準の設定では直接実行できない、というのも取っつきにくいと思います。

しかし、コマンドレットや.NetFrameworkによって提供される機能は強力で、実務でもWindowsPowerShellのスクリプトを見かけるようになってきています。
なので、WindowsPowerShellにも慣れておいた方が無難ではないかと思います。

便利な機能があれば、今後紹介していこうと思います!

クラス図とjavaソースの対応一覧

クラス図とはUMLの一種で、以下のような形でクラスの定義と各クラスの関係を表す設計図のことです。

今回は、クラス図で使われる記法とjavaソースの対応について、一覧にしてみました。
参考になれば幸いです。

【クラス定義】

【各クラスの関係】


いかがでしたでしょうか?

クラス図を書かなくともjavaのプログラムは作れてしまうので、情報を伝達したり整理したりするためにクラス図を書かなければならないとなった時に書き方を忘れてしまうことは意外とあると思います。
javaのプログラムに慣れた方であれば、日本語で説明されるよりもソースで説明された方がわかりやすいと思ったので、このような記事を書いてみました。

java:関数を引数として渡す

C#では、こちらの記事のようにdelegateの仕組みを利用して関数を変数として扱うことができます。
例えば、引数と引き渡してコールバック処理を実現することができます。

javaでも、8以降であれば関数型インターフェースを利用して関数を変数として扱うことができます。
以下、サンプルコードです。

【サンプルコード】

・FunctionMain.java

【実行結果】


上記のようにFunction型を用いるのが基本的な形なのですが、いくつか発展的な記法が存在します。

例えば、引数と戻り値が同じ型である場合は、UnaryOperator型を使用することでジェネリクスの表記を省略することができます。
(他にも、戻り値がvoidの場合に適用できるConsumer型、戻り値がboolean型の場合に適用できるPredicate型等が存在します)

また、引き渡す関数をラムダ式で表記することで、関数の定義を省略することができます。

【サンプルコード】

・FunctionMain.java

【実行結果】


いかがでしたでしょうか。

最近ではJava8以降の文法が使われる機会が多く、今回紹介したような関数型インターフェースも使われることが少なくありません。
従来のJavaと比べると書き方が独特に感じるかもしれませんが、慣れておくと実際の案件で困ることが少なくなると思います。