早く読み終わらなければ...第2版が出てしまう!
前回からの続き。
--------------
19.Cの構造体をクラスで置き換え
要するにアクセサ無しのpublicなインスタンスフィールドを持つクラスについて。
パッケージプライベートやprivateなネストクラスなら使っても良いんじゃない?というお話。
--------------
20.共用体をクラス階層で置き換え
そもそも共用体ってなんだっけと思ってしまった。かなり忘れてる。同じメモリ領域を複数の型で扱えるようする型のことなんだけど、{列挙型によるタグ+共用体}を持つ構造体をタグ付き共用体と呼ぶらしい。この項目では、タグ付き共用体でJavaの多態性を実現するのは難しいという点を挙げ(Javaで言うところのinstanceof地獄)、このタグ付き共用体をクラス階層に置き換える話をしている。
タグ付き共用体を構成しているものはそれぞれ
タグ付き共用体→abstractクラス
タグが表すモノ、つまり共用体の要素となるのもの→上記のabstractクラスを継承する具象クラス ...に置換できる。
最後にCのタグ付き共用体とJavaの方で実現したクラス階層の比較検討。
(型の安全性、大量のswitch文がJVMによるメソッドディスパッチによってスッキリ消えるという点で後者の方が優れてる。)
--------------
21.intによる列挙型をタイプセーフ列挙型に
1.5からJavaでもenumが導入されたので陳腐化してしまった項目。というかこの項目で説明している内容が本家に取り込まれたといっていい。
それでも内容はなかなか面白い。
無名クラスを活用して列挙型の各要素に振る舞いを持たせて挙げてる例とか。
→singletonにしてパフォーマンスを向上させている。
→更に発展してシリアライズによるオブジェクトの重複をreadResolve()を使って防ぐコード例の提示。(でも列挙型をシリアライズなんかする場合ってあるのか?)
→更に更に継承とかして拡張する例も。
この項目の最後では「列挙型はそんな使うモノじゃない。項目20のようにswitch文を大量に書くならoopによるメソッドディスパッチに置き換えるべきだ」というなんか掌を思いっきり返されたような結論で終わってる。
[おまけ]
|演算のおいしい使い方
フルーツ2種、野菜2種あったとして
int melon = 1; //メロン
int grape = 2; //グレープ
int cabbage = 4; //キャベツ
int cucumber = 8; //きゅうり
int fruit = melon | grape ;
ってやればintだけで集合が表せる!しかも高速!
BinaryHackとか読んでいたときもこの手の書き方って出ていたけど具体的にどんな感じに使うのかしらんかったのでビットのor演算による集合の表し方の話は参考になった。各要素が全部2のベキ乗なのがミソですね。
ちなみに1.5以降のenum要素を使って集合体を表現したかったらjava.util.EnumSet クラスか java.util.EnumMap クラスを使う。この辺は「J2SE 5.0 Tiger 虎の穴 Typesafe Enum」参照。
--------------
22.Cの関数ポインタをクラスとインタフェースで置換
状態を持たず(stateless)、メソッド1つだけなクラスのオブジェクト→Cの関数ポインタと実質同じ。
Cのqsortに渡すcomparator相当はインタフェース(strategy interface)と具象戦略クラス(concrete strategy)に分離させる(GoFのStrategyパターン)
具象戦略クラスは状態を持たないので、大抵singletonになれる。
p108-109にコード例(ただし、JDK1.5以降はgenericsにより、引数の型をObjectにするのは古い書き方になる。キャストで実行時エラーを発生させる可能性を残すよりも、コンパイルの段階ではじいた方がイイだろう。)
例えばsortメソッドに渡す具象戦略クラス(comparator)を作るとしたらどうやってつくろうか?
-ソートする場所が限られてるならソートを行うクラスのprivate static メンバークラスに。
-場所に加えて回数も限られてるならソートする箇所で無名クラスとして宣言しちゃってもいいカモね。
-そうでないなら、comparatorはpublicなトップレベルのクラスの分離すべき。