Autonomous Solutions Inc.のソフトウェア開発者Brannon B. King氏は2014年5月のMSDN MagazineでC#でSOLIDの原則に反することの危険性と題した記事を公開した。著者は、開発者のミスでC#コードがSOLIDの原則を破ることで、拡張または維持することがより難しくなる概要を説明した。
King氏は、カウンターコードのサンプルとすべてのSOLIDの原則のためのアドバイスを提供したが、簡潔にするためにオープン・クローズドの原則(OCP)に関係した一部を抽出した。OCPでは、"ソフトウェア エンティティ (クラス, モジュール, 関数など)は、拡張のためにオープンでだが、変更にはクローズであるべき"と位置づけている。King氏によると、以下のコードはOCPを破壊する。
void DrawNerd(Nerd nerd) {
if (nerd.IsSelected) DrawEllipseAroundNerd(nerd.Position, nerd.Radius);
if (nerd.Image != null) DrawImageOfNerd(nerd.Image, nerd.Position, nerd.Heading);
if (nerd is IHasBelt) // a rare occurrence
DrawBelt(((IHasBelt)nerd).Belt);
// Etc.
}
なぜなら“あなたが、顧客が新しいものを表示するニーズがあるたびにこのメソッドを変更する必要がある”ため、代わりに描画するための汎用的なプロシージャーを提案する:
readonly IList<IRenderer> _renderers = new List<IRenderer>(); void Draw(Nerd nerd) { foreach (var renderer in _renderers)
renderer.DrawIfPossible(_context, nerd); }
このアイディアは
…よく知られたインターフェイスを実装した描画クラス(または描画に関するクラス)を書きます。レンダラーは、入力に応じてなにを書くかを判断するために、賢くある必要があります。たとえば、ベルトを描画するコードは、インターフェイスをチェックして、必要に応じて進める“ベルトレンダラー”に移動することができます。
OCPを破壊するその他の例は、継承クラスを参照するクラスである。
class Nerd {
public void DanceTheDisco() {
if (this is ChildOfNerd)
throw new CoordinationException("Can't");
...
}}
class ChildOfNerd : Nerd { ... }
著者のアドバイスは“基底クラスを直接継承先から参照してはならない。”ということである。この問題はピアクラスで表すことができる:
class NerdsInAnArc {
public bool Intersects(NerdsInAnLine line) {
...
}
...
}
King氏は説明する:
Arcsとlinesは一般的にはオブジェクト階層でピアです。相互について親密に知るべきではなく、それらの詳細は、最適な共有アルゴリズムで必要になることがあります。他を変更することなく、自由に変更できるようにしておきます。これはまた、単一責務の原則に違反します。あなたはarcsをストアしますか、それともそれを分析しますか?独自のユーティリティクラスに分析操作を含めます。
小さなプロジェクトでは、SOLIDの原則を厳格に適用する必要はないかもしれないが、大きなコードベースでは、さらに重要になり、“スパゲッティ”コードを避けることは非常に望ましい。