私のコードの約3分の1はFacadeクラスにラップされています。これは「神」クラスではなく、実際には1つのもの(Line
と呼ばれる)を表すことに注意してください。当然、その背後にあるサブシステムに責任を委任します。
最終的に発生するのは、2つのサブシステムクラス(Output
とTimeline
)のすべてのメソッドがLine
クラスで複製されているため、Line
がOutput
とTimeline
の両方になります。 Output
インターフェイスとTimeline
インターフェイスを作成して、Line
クラスが両方を実装できるようにすることは理にかなっているようです。同時に、並列クラスとインターフェース構造を作成することも心配です。
ご覧のとおり、行AudioLine
、VideoLine
にはさまざまなタイプがあり、すべて同じタイプのTimeline
を使用していますが、異なるタイプのOutput
(それぞれ、AudioOutput
とVideoOutput
)を使用しています。つまり、AudioOutputInterface
とVideoOutputInterface
も作成する必要があるということです。したがって、並列クラス階層が必要になるだけでなく、並列インターフェース階層も必要になります。
この設計上の欠陥に対する解決策はありますか?
基本的な構造のイメージを次に示します(Timelineクラスを除いて、各Lineにはタイムラインがあることを知っています)。
注:Timeline
のWord'line 'は、Line
クラスと同様の機能を実行しているように聞こえるかもしれません。明確にするためだけに、そうではありません。
タイムラインとして主にLineに関心を持つクライアントもいれば、Outputとして主に関心を持つクライアントもいますか?もしそうなら、それとクライアントの間に立つLineからのクラスまたはインターフェースの発芽を検討してください。これらの新しいクラスはそれぞれ、Lineへのポインターをラップし、APIに焦点を合わせながら実装を抽象化します。
最初は、ファサードのファサードのように感じますが、それは新しいリファクタリングの視野を開きます。 Lineから新しいクラスにメソッドをプルできます。抽出できる新しいヘルパークラスを見つけることができます。おそらく、実装クラスの1つがここにも属していることがわかります。
最終的に発生するのは、2つのサブシステムクラス(出力とタイムライン)のすべてのメソッドがLineクラスで複製されているため、Lineが出力とタイムラインの両方になります。
上記の文は悪いデザインのように聞こえます。
Facadeクラスのほとんどのメソッドは、複数のサブシステムクラス、または少なくとも1つのサブシステムクラスの複数のメソッドで呼び出されると思います。
ファサードが多くの単純な委任を行っている場合(たとえば、ファサードメソッドdoSomething
が別のクラスのdoSomething
を呼び出すだけ)、おそらくリファクタリングする必要があります。
具体的には、デリゲートクラスが残りのサブシステムと対話しない場合、クライアントはファサード経由ではなく、おそらく直接デリゲートと対話する必要があります。
私は他の両方の答えに本当に同意します。ここでの主な問題は、Line
には複数の責任があることです。あなたは、クラスが「物」に対応していると信じるという誤謬に陥っていますが、実際にはクラスは「責任」に対応しているはずです。
そうは言っても、「クライアントコードを簡素化するために、他のいくつかのクラスに委任する単一のファサードを提供する」という単一の責任をクラスが持つことは確かに可能です。それはあなたが説明していることかもしれないように聞こえます。委任の他に、Line
が独自の動作をするかどうかによって異なります。クライアントコードが複数のオブジェクトと通信するのは面倒ではないので、私は通常これを行いませんが、それは個人的な好みに合わせて行われる可能性があります。
Lineクラスが両方を実装できるように、OutputインターフェイスとTimelineインターフェイスを作成することは理にかなっているようです。同時に、並列クラスとインターフェース構造を作成することも心配です。
何があなたにそれをする動機を与えますか?その変更の必要性はありますか、それとも「もっと正しい」と思うだけですか?後者の場合、私はあなたのコードをそのままにしておきます。作業コードが重要です。