このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
これで、通常のショートカットと、
インターネットショートカットの 2 つを読めるようになった。
LinkTargetColumn に実装してテストと行きたいところだが、
少しコードが増えてきたので、
カラムの実装の前に、リファクタリングを行おう。
クラスの設計というのは、基本的には難しい。
技術的に難しいということではなく、
考え方次第ではいくつも答えがあることが難しいのだ。
クイズのように特定の正解が存在するわけではない。
俺は、オブジェクト的な考え方をするのは苦手なほうだ。
なので、最初からクラスとして設計するのではなく、
まずはとりあえず実装してから、
後で徐々に分割していく手法をよく使う。
今日は LinkTargetColumn の実装分割をやろう。
InternetShortcutClass を使えば、リンク先の取得はできる。
しかし、それをそのまま LinkTargetColumn に入れると、
コードが長くなり、読みにくくなってくる。
public override object GetValue(ref SHCOLUMNDATA pscd) {
(…省略…)
switch (pscd.pwszExt.ToLower()) {
case ".lnk":
(…lnk ファイルを読む長いコード…)
return ~;
case ".url":
(…url ファイルを読む長いコード…)
return ~;
default:
throw new ComFalseException();
}
このようにメソッド内に大きな switch ができてしまうのだ。
こういう場面に遭遇したら、それは実装分割のチャンスだ。
あくまでもチャンスなので、あらゆる switch を
分割しなければならないわけではないが、
殆どの場合、それはいい機会となる。
まず、最初に思いつくのが、ショートカット先の取得を
ヘルパメソッドとして分割することだ。
メソッドとして分けるだけでも見通しが良くなる。
分割は、以下のように考えて行う。
・switch が行う目的を単純にし
各 case で行う処理を整理する。
単純化できない場合は、複数の switch に分ける。
⇒ファイルを読んで、リンク先を得るってのが目的だ。
・switch ごと他のメソッドに引っ越すのではなく、
switch の各 case 内を、個別のメソッドに移動する。
メソッドのシグネチャはばらばらでもかまわない。
⇒ファイルごとに扱いが異なるので、
拡張子ごとにわけるのが自然だ。
・可能であれば、default も分割する。
⇒対応していないファイル形式の場合、
ただ単に例外を発生させるメソッドを作る。
・分割されたメソッドが、フィールドに依存する場合、
メンバメソッドとして定義する代わりに、
static メソッドとしてフィールドを引数として渡す。
⇒今回はフィールドに依存することはない。
こういう風に分割する。まあ役割分担だ。
こうして分割したメソッドは、独立性の高い関数となる。
完全に引数にしか依存しない独立性の高い関数は、
別のクラスに移動することもできるのだ。
いわば、グローバル関数のような位置づけにする。
まあ、C# では、グローバル関数は認められないけどね。
public override object GetValue(ref SHCOLUMNDATA pscd) {
(…省略…)
switch (pscd.pwszExt.ToLower()) {
case ".lnk":
return GetShortcutTarget(pscd.wszFile);
case ".url":
return GetInternetShortcutTarget(pscd.wszFile);
default:
return GetOtherTarget();
}
}
static private string GetShortcutTarget(string path) {
(…省略…)
}
static private string GetInternetShortcutTarget(string path) {
(…省略…)
}
static private string GetOtherTarget() {
throw new ComFalseException();
}
まず、これが一段階だ。
実は、別にこれだけでもいいのだ。
見通しが良くなっているだけでも十分である。