しかし、draw()メソッドは、ユーザーインターフェースに大きく依存していませんか?
実用的な観点から見ると、システム内の一部のコードはRectangle
、ユーザーエンドの要件である場合のように描画する方法を知る必要があります。そして、それはある時点で、ピクセルのラスタライズやコンソールでの何かの表示のような本当に低レベルのことを行うことに要約されます。
カップリングの観点からの私への質問は、このタイプの情報に誰が/何を依存すべきか、そしてどの程度の詳細(例えば、どの程度抽象的か)ですか?
描画/レンダリング機能の抽象化
上位レベルの描画コードが非常に抽象的なものにのみ依存している場合、その抽象化は、ターゲットとするすべてのプラットフォームで(具体的な実装の置換により)動作する可能性があるためです。考案された例として、非常に抽象的なIDrawer
インターフェイスをコンソールとGUIの両方のAPIで実装して、プロット形状などを実行できる場合があります(コンソール実装はコンソールをASCIIアートの80xNの「イメージ」のように扱う場合があります)。もちろん、それは不自然な例です。なぜなら、通常はコンソール出力を画像/フレームバッファーのように扱うことではないからです。通常、ほとんどのユーザーエンドは、コンソールでより多くのテキストベースの対話を要求する必要があります。
別の考慮事項は、安定した抽象化を設計するのがどれほど簡単かということです。対象とするのは、ライン、長方形、パス、テキスト、この種のもの(プリミティブの限られたセットの単純な2Dラスタライズ)のような基本的な図形描画機能を抽象化する最新のGUI APIだけであれば簡単かもしれません、さまざまなサブタイプを介して簡単に実装できる1つの抽象インターフェースを、低コストで提供します。そのような抽象化を効果的に設計し、すべてのターゲットプラットフォームに実装できる場合、シェイプやGUIコントロール、またはそのような抽象化。
しかし、プレイステーションポータブル、iPhone、XBox One、パワフルなゲームPCの間で変化する厄介な詳細を抽象化しようとしている一方で、ニーズはそれぞれに最先端のリアルタイム3Dレンダリング/シェーディングテクニックを利用することであるとします。その場合、基礎となるハードウェアの機能とAPIが非常に大きく変化するときにレンダリングの詳細を抽象化する1つの抽象インターフェイスを考え出そうとすると、設計と再設計に膨大な時間がかかり、予期せずに設計変更が繰り返される可能性が高くなります発見、同様に、基盤となるハードウェアの完全な一意性と能力を活用できない最も一般的な分母ソリューション。
安定した「簡単な」設計への依存関係の流れの作成
私の分野では、私はその最後のシナリオにいます。私たちは根本的に異なる基本的な機能とAPIを備えた多くの異なるハードウェアをターゲットにし、それらをすべて支配する1つのレンダリング/描画抽象化を考え出すことは境界線絶望です(ゲームのように効果的にそれを行うだけで世界的に有名になるかもしれません業界のチェンジャー)。ですから、私の場合、私が最後に望むことは、たとえそのドローイングを可能な限り最高レベルで最も抽象的な方法で表現しているとしても、アナロジーShape
やModel
、Particle Emitter
自分自身を描く方法を知っているようなものです...
...これらの抽象化は適切に設計するのが難しすぎるため、設計を修正するのが困難で、すべてがそれに依存している場合、それは最もコストのかかる中央設計変更のレシピであり、それに応じてすべてを波及させ破壊するからです。したがって、最後にしたいことは、システム内の依存関係が、修正するのが難しすぎる抽象設計に向かって流れることです(侵入的な変更なしに安定させるのが難しすぎます)。
難しいは簡単に依存しているが、簡単ではないは難しいに依存している
したがって、代わりに行うことは、依存関係を設計しやすいものに向かって流れさせることです。ポリゴンやマテリアルのようなものを保存することに焦点を合わせた抽象「モデル」を設計し、その設計を正しくするのは、図面をサービスするために効果的に実装できる抽象の「レンダラー」を設計するよりもはるかに簡単ですPCからPSPのような異種ハードウェアを均一に要求します。

そのため、設計が難しいものから依存関係を反転させます。抽象モデルに、すべてが依存する抽象レンダラーデザインに自分自身を描画する方法を知らせるのではなく(そして、その設計が変更されると実装を中断する)、代わりにシーン内のすべての抽象オブジェクトを描画する方法を知っている抽象レンダラーがあります(モデル、パーティクルエミッタなど)、などのPC用のOpenGLレンダラーサブタイプを実装できますRendererGl
。別のPSP RendererPsp
用、携帯電話用などに依存します。その場合、依存関係は安定した設計に向かって流れ、修正が容易で、レンダラーから、シーン内のさまざまなタイプのエンティティ(モデル、パーティクル、テクスチャなど)まで。

- 私が理解できる限り、変化の難しさをより多く測定しているボブおじさんの求心性/遠心性カップリングメトリックとは少し異なる意味で「安定性/不安定性」を使用しています。私は「変更を必要とする確率」についてもっと話していますが、彼の安定性の指標はそこで役立ちます。「変更の確率」が「変更の容易さ」に比例する場合(例:変更を必要とする可能性が最も高いものは、最も不安定であり、ボブおじさんの測定基準からの求心性結合)、そのような可能性のある変更は、安価で邪魔にならない、中心的な設計に触れることなく実装を置き換えるだけで済みます。
コードベースの中央レベルで何かを抽象化しようとしていて、壁に頭をぶつけて、毎月/年に8,000のソースファイルを更新する必要のある変更を絶えず行うのではなく、設計が非常に難しい場合それに依存するすべてを壊す、私の一番の提案は、依存関係を反転することを検討することです。設計が非常に困難なものは、設計が他のすべてのものに依存し、設計が非常に困難なものに応じて設計が容易なものを持たないような方法でコードを記述できるかどうかを確認します。実装ではなく設計(具体的にはインターフェース設計)について話していることに注意してください。時には、設計が簡単で実装が難しい場合があります。また、時には設計が難しくても実装が簡単な場合があります。依存関係は設計に向かって流れるので、依存関係が流れる方向を決定するためにここで何かを設計することがどれだけ難しいかに焦点を当てる必要があります。
単一責任の原則
私にとって、SRPは通常はそれほど興味深いものではありません(ただし、コンテキストにもよりますが)。目的が明確で保守Shape
可能なものを設計する際に綱渡りのバランスをとる行為がありますが、オブジェクトは、たとえば、自分で描く方法がわからない場合、より詳細な情報を公開する必要があり、あまり意味のあることはないかもしれません特定の使用コンテキストで形状を作成し、それを描画するよりも実行します。ほぼすべてとトレードオフがあり、特定のコンテキストでの私の経験では、このようなメンテナンスの悪夢になり得る自分自身を描く方法を意識させることができるSRPとは関係ありません。
それは、カップリングと、システム内で依存関係が流れる方向に関係しています。すべてが依存する抽象的なレンダリングインターフェイスを(自分自身で描画するために使用しているため)新しいターゲットAPI /ハードウェアに移植しようとしており、そこで効果的に機能するためにデザインを大幅に変更する必要があることに気付いた場合、それは非常にコストのかかる変更であり、自分自身を描く方法を知っているシステム内のすべての実装を置き換える必要があります。そして、それは、前もって正しく設計するのが難しすぎる抽象化に向かって流れる依存関係のボートの負荷に変換される場合、自分自身を描く方法を知っているもので遭遇する最も実用的なメンテナンスの問題です。
開発者の誇り
私の経験では、これは多くの場合、依存関係の方向を設計しやすいものに向けることの最大の障害であるため、この1つの点に言及します。開発者がここで少し野心的になり、「クロスプラットフォームレンダリングの抽象化を設計してすべてを支配し、他の開発者が何ヶ月もポーティングに費やすものを解決します。そして、それは正しく、私たちがサポートするすべてのプラットフォームで魔法のように動作し、すべてのプラットフォームで最先端のレンダリング技術を利用します。私はすでにそれを頭の中で思い描いていました。」その場合、彼らはそれを避けて依存関係の方向を反転させ、莫大な費用がかかり、繰り返し発生する中央の設計変更を単に安価でローカルな繰り返しの実装変更に変換するという現実的な解決策に抵抗します。そのような抽象的なレベルまで設計するのが難しすぎるとあきらめて、戦略全体を再考する開発者には、ある種の「白旗」の本能が必要です。そうでなければ、彼らは多くの悲しみと痛みに陥ります。このような世界を征服する野心をインターフェースの設計レベルに引き上げるよりも、そのような野心と闘志を、設計しやすいものの最先端の実装に移すことをお勧めします。