カプセル化によるルールの強制

オブジェクト指向を適用すると、ソースコードの重複した記述を排除でき、生産性や品質を向上することができます。
それとは別に、他の開発者にルールを強制できるメリットもあります。
カプセル化を例にして説明するのがわかりやすいので、今回はカプセル化を例に挙げてルールを強制するメリットを書いていきます。


例えば、自分は商品の金額を計算するPriceCalcクラスを作成していて、他の開発者はPriceCalcクラスを利用するUserクラスを作成しているとします。
自分としては「このロジックで金額計算して欲しい」というのがあるのですが、他の開発者にそのロジックの実装をさせるようにしてしまうと、意図が上手く伝わらなかった時に誤ったロジックで計算されてしまいます。
この状況をソースコードで表すと下記のような形になり、PriceCalcクラスは計算に必要な変数をまとめるだけ、PriceCalc側でその変数を参照して独自に業務ロジックを実装するような形となります。


それでは困るので、クラス変数に付随する業務ロジックもPriceCalcクラス側に実装することにします。
変数とメソッドをひとまとまりにして一つのクラスとして提供することで、Userクラス側ではメソッドを呼び出すだけであるべき業務ロジックに基づいた計算を行うことができ、Userクラス側で業務ロジックを意識する必要が無くなります。

しかし、メンバ変数がpublicだと、Userクラス側でその変数を参照して独自に業務ロジックを実装することもできてしまいます。
自分としてはそれでは困るので、「変数を参照して独自に業務ロジックを実装しないでください」と伝えるのですが、それが上手く伝わらないと独自に業務ロジックを実装されてしまう可能性があります。
自分一人でプログラムを作っている場合は全ての変数をpublicにした方が便利だったりもしますが、複数人で開発している場合は意思疎通がうまく行かなかった場合に意図通りではないコーディングをされてしまうリスクがあります。


それを防ぐためには、変数のアクセスレベルをprivate等にして、変数に自由にアクセスできないようにするのが有効です。
こうすることで、変数を参照して独自に業務ロジックを実装しようとされた場合に、コンパイルエラーとして機械的に失敗させることができます。
これが、カプセル化によるルールの強制であり、意思疎通がうまく行かなかった場合に意図通りではないコーディングをされるリスクを減らすことができます。


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

一人で開発する時と複数人で開発する時では、気を付けるべきポイントが変わることがあります。
オブジェクト指向の考え方の一つである「カプセル化」も、単なる慣習として捉えるのではなく、複数人で開発する場合にルールを規定するものとして捉えることで、実務で有効に使えるのではないかと思います。

java:ソートキーが複数存在する場合、一時的なフォーマット変更ではなく独自Comparatorで対応するべき

複数のソートキーが存在するオブジェクトの配列について、固定長のフォーマットに直すことでソートキーを1つにできます。
しかし、フォーマットを直して1つのキーでソートできるようにするよりも、独自Comparatorを定義して複数のキーでソートした方が高速なので、そのようなケースでは独自Comparatorを定義して対応するべきです。

単純にフォーマット変更でコストがかかるだけでなく、ソート処理自体も複数のキーでソートした方が高速です。
複数のキーを1つのキーにまとめてソートする場合は必ずキー全体を見る必要がありますが、複数のキーでソートする場合はキーの一部を見るだけでソートできる場合があるので、複数のキーでソートした方が高速になるのだと思います。

以下、テスト結果です。

【ソースコード】

・SortTest.java

・SortTestRecord.java

・SortTestComparator.java

【結果(1回目)】

【結果(2回目)】

【結果(3回目)】

【結果まとめ】


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

昔に固定長フォーマットに直してまとめてソートするという手法を実務で見かけたので試してみましたが、この手法はやめた方が良さそうなことがわかりました。
ソート処理自体も複数のキーでソートした方が高速だというのは意外でした。

Java:任意の順番でのソート

JavaのCollection型(サブクラスにList型等がある)は、Collections.sortメソッドでソートすることが可能です。
Collections.sortメソッドは、第一引数にソートしたいCollection型のオブジェクト、第二引数にComparator型のオブジェクトを渡します。
第二引数のComparator型のオブジェクトにより、ソート順が決まります。

Collections.sortメソッドでは、Comparator型のcompareメソッドを利用してソートを行います。
ソート順を定義するためには、Comparator型を実装したクラスを独自に作成し、compareメソッドをオーバーライドして独自のロジックを記述する必要があります。
compareメソッドの説明は以下です。
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Comparator.html#compare-T-T-
簡単に言うと、compareメソッドの第一引数と第二引数について、戻り値がマイナスの値の場合は「第一引数→第二引数」の順番に並び、戻り値がプラスの値の場合は「第二引数→第一引数」の順番に並びます。

これを利用して、任意の順番でソートを行うサンプルが以下になります。

【サンプルコード】

・MySortMain.java

・MySort1.java

・MySort2.java

【実行結果】


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

javaで独自順のソート処理をする機会があったので、実装方法を簡単に書いてみました。
Comparatorインターフェースのcompareメソッドを実装すること、compareメソッドの戻り値によりソート順を定義すること、を抑えれば、何をしているか理解できると思います。

Base64の説明とjavaでのエンコード・デコードの例

Base64とは、テキストデータやバイナリデータ(画像ファイル、PDFファイル等)を表現する方式の一つです。
以下の64種類の文字と末尾のパディング文字(=)を用いて表現するのが特徴です。
・アルファベット(a~z, A~Z)
・数字(0~9)
・一部の記号(+, /)

この表現方式は、一部の文字しか使用できないプロトコルでデータの送受信を行いたい場合に有用であり、ASCII文字しか送受信できないプロトコルでもデータの送受信が可能になります。
有名な所で言うと、電子メール(SMTP)でBase64が使われています。
また、APIでのデータ送受信でも良く使われます。

ここで、Base64のエンコード・デコードをイメージしやすくするため、2バイト文字(日本語)をJava8 の java.util.Base64を用いてエンコード・デコードしてみます。

【サンプルコード】

・Base64Test.java

【実行結果】


なお、今回の記事では触れませんが、バイナリファイルを1バイトずつエンコード・デコードすることで、バイナリデータにも対応できます。
また、Base64のエンコード・デコードの方式は公開されており、人気の言語ではライブラリも存在しているので、他の言語でも実装可能です。


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

Base64については入門書で触れられることが少なく、情報処理技術者試験でも午前問題で稀に出題される程度なので、実務で初めて耳にする方は少なくないと思います。
「Base64を使えば画像や動画もASCII文字(1バイト文字)で表現できる」というざっくりな知識だけでも覚えておけば、実務でもスムーズにコミュニケーションできるかと思います。

java:通常のクラスと匿名クラス(無名クラス)の書き方の比較

以前の記事で「通常のクラスと匿名クラスの書き方の比較を見たい」という意見があったので、少し補足を行います。

サンプルコードの通り、匿名クラスの場合、クラスに名前を付ける必要が無く、またオブジェクト生成と同時に処理を定義することができます。
これにより、以下のようなメリットがあります。

  • 記述を簡潔にできる
  • 使い捨てのクラスを定義でき、使い捨てであるという意図も明確にできる
  • (ソースファイル名とクラス名を同じにする場合)管理が容易になる

【サンプルコード】

・AnonymousClass.java

・AnonymousSubClass.java

・AnonymousInterface.java

・AnonymousImplementsClass.java

・AnonymousMain.java

【実行結果】


良い意見やコメントを頂いた時は、今回のような形で答えていきたいと思います!