web-dev-qa-db-ja.com

回避するパターンを設計する

多くの人々は、シングルトンパターンには多くの欠点があり、パターンを完全に回避することを示唆する人もいることに同意しているようです。 ここでの素晴らしい議論 があります。その質問にシングルトンパターンに関するコメントを送信してください。

私の質問:他の設計パターンはありますか、それは避けるか、細心の注意を払って使用する必要がありますか?

105
Brian Rasmussen

パターンは複雑です

すべての設計パターンは注意して使用する必要があります。私の意見では パターンにリファクタリングする必要があります パターンをすぐに実装する代わりにそうする正当な理由がある場合。パターンの使用に関する一般的な問題は、パターンが複雑になることです。パターンを使いすぎると、特定のアプリケーションまたはシステムをさらに開発および保守するのが面倒になります。

ほとんどの場合、簡単な解決策があり、特定のパターンを適用する必要はありません。良い経験則は、コードの一部が置き換えられたり、頻繁に変更される必要があるときはいつでもパターンを使用し、パターンを使用するときに複雑なコードの警告を受ける準備をすることです。

目標は単純であること であり、コードの変更をサポートする実際的な必要性がある場合はパターンを使用することを忘れないでください。

パターンの原則

明らかに過剰に設計された複雑なソリューションにつながる可能性がある場合、パターンを使用することは無意味に思えるかもしれません。しかし、プログラマーにとっては、ほとんどのパターンの基礎となる設計手法と原則を読むほうがはるかに興味深いです。実際、私の 「デザインパターン」に関するお気に入りの本はこれを強調しています 問題のパターンに適用できる原則を繰り返して説明しています。これらは、関連性の点でパターンよりも役立つほど単純です。コードのモジュールを構築できる限り、 Liskov Substitution Principle など、オブジェクト指向プログラミング(OOP)以上のものを包含するのに十分な原則がいくつかあります。

多数の設計原則がありますが、 GoF本の最初の章 で説明されているものは、最初から非常に役立ちます。

  • 「実装」ではなく「インターフェース」にプログラムする。(Gang of Four 1995:18)
  • 「クラス継承」よりも「オブジェクト構成」を優先する。(Gang of Four 1995:20)

それらをしばらくの間あなたに沈めましょう。 GoFが記述されたときに interface は抽象化(スーパークラスも意味する)を意味し、JavaまたはC#。2番目の原則は、 残念ながら今日でも一般的 である、観察された継承の過剰使用に由来します。

そこから SOLID原則 について読むことができます。これはRobert Cecil Martinによって知られています (aka。Uncle Bob) 。 Scott Hanselmanは、ボブおじさんに これらの原則に関するポッドキャスト :でインタビューしました。

  • [〜#〜] s [〜#〜]single Responsibility Principle
  • [〜#〜] o [〜#〜]ペンの閉じた原理
  • [〜#〜] l [〜#〜]iskov置換原理
  • [〜#〜] i [〜#〜]インターフェイス分離の原理
  • [〜#〜] d [〜#〜]異常逆位の原理

これらの原則は、読み進めて仲間と議論する良い出発点です。原則は、相互に、および 懸念の分離依存性注入 などの他のプロセスと織り交ぜられていることがあります。 [〜#〜] tdd [〜#〜] を実行した後、作成するためにある程度に従う必要があるため、これらの原則が実際に自然に来ることもありますisolatedおよびrepeatable単体テスト。

147
Spoike

Design Patternsの作者自身が最も心配したのは、「Visitor」パターンでした。

それは「必要な悪」です-しかし、しばしば使いすぎであり、その必要性はしばしばあなたのデザインのより根本的な欠陥を明らかにします。

「Visitor」パターンの代替名は「Multi-dispatch」です。これは、Visitorパターンが、単一タイプのディスパッチOO言語を使用して2つ(またはそれ以上)の異なるオブジェクトのタイプに基づいて使用するコード。

古典的な例としては、2つの形状の交差点がありますが、見過ごされることが多いさらに単純なケースがあります。2つの異種オブジェクトの等価性を比較することです。

とにかく、多くの場合、次のような結果になります。

interface IShape
{
    double intersectWith(Triangle t);
    double intersectWith(Rectangle r);
    double intersectWith(Circle c);
}

これに関する問題は、「IShape」のすべての実装を結合していることです。階層に新しいシェイプを追加する場合は、他のすべての「Shape」実装も変更する必要があることを暗示しています。

時々、これは正しい最小設計です-しかしそれを考えてください。あなたのデザインは実際に 2つのタイプでディスパッチする必要があるとしていますか?マルチメソッドの組み合わせの爆発のそれぞれを書いて喜んでですか?

多くの場合、別の概念を導入することで、実際に記述する必要がある組み合わせの数を減らすことができます。

interface IShape
{
    Area getArea();
}

class Area
{
    public double intersectWith(Area otherArea);
    ...
}

もちろん、それは依存します-時にはそれらの異なるすべてのケースを処理するためにコードを書く必要があります-しかし、思い切ってVisitorを使う前に一時停止して考える価値があります。それは後であなたの多くの痛みを救うかもしれません。

21

シングルトン-シングルトンXを使用するクラスには依存関係があり、テストのために見にくく分離するのが困難です。

便利で理解しやすいため、非常に頻繁に使用されますが、テストは本当に複雑になります。

シングルトンは病理学的嘘つき を参照してください。

16
orip

Template Methodパターンは一般的に非常に危険なパターンだと思います。

  • 多くの場合、「間違った理由」のために継承階層を使い果たします。
  • 基本クラスには、あらゆる種類の無関係なコードが散らばる傾向があります。
  • 多くの場合、開発プロセスのかなり早い段階で、設計をロックダウンする必要があります。 (多くの場合、早すぎるロックダウン)
  • 後の段階でこれを変更することは、ますます難しくなります。
14
krosenvold

設計パターン(DP)を避けるべきではないと思います。また、アーキテクチャを計画するときに、DPを使用するように強制するべきではないと思います。 DPは、計画から自然に出現した場合にのみ使用する必要があります。

特定のDPを使用することを最初から定義する場合、将来の設計決定の多くはその選択の影響を受けますが、選択したDPがニーズに適しているという保証はありません。

また、DPを不変のエンティティとして扱うこともできません。パターンをニーズに適合させる必要があります。

したがって、要約すると、DPを避けるべきではないと考えています。DPが既にアーキテクチャで形をとっているときに、それらを受け入れるべきです。

9
Megacan

Active Recordは、ビジネスロジックと永続化コードの混合を促進する使い古されたパターンだと思います。ストレージの実装をモデルレイヤーから隠し、モデルをデータベースに結び付けるという非常に良い仕事をしていません。テーブルデータゲートウェイ、行データゲートウェイ、データマッパーなど、多くの代替手段(PoEAAで説明)があります。これらは多くの場合、より優れたソリューションを提供し、ストレージのより優れた抽象化の提供に役立ちます。また、モデルはneedをデータベースに保存しないでください。 XMLとして保存したり、Webサービスを使用してアクセスしたりするのはどうですか?モデルの保存メカニズムを変更するのはどれくらい簡単ですか?

とは言っても、Active Recordは必ずしも悪いわけではなく、他のオプションでは使い物にならない単純なアプリケーションに最適です。

7
Tim Wardle

それは簡単です...あなたにとってはっきりしないまたはあなたが快適に感じないであるデザインパターンを避けてくださいin

いくつかの名前を付けるには...

いくつかの非実用的なパターンがあります、例えば:

  • Interpreter
  • Flyweight

いくつかの把握するのが難しいもあります、例えば:

  • Abstract Factory-作成されたオブジェクトのファミリーを含む完全な抽象ファクトリーパターンは、それほど簡単ではないようです
  • Bridge-抽象化と実装がサブツリーに分割されている場合、抽象化しすぎる可能性がありますが、場合によっては非常に有用なパターンです
  • Visitor-二重ディスパッチメカニズムの理解は本当に必須です

また、非常に単純に見えるパターンもありますが、それほど明確ではない選択原則または実装に関連するさまざまな理由のため:

  • Singleton-完全に悪いパターンではなく、TOOが過度に使用されているだけです(多くの場合、適切ではありません)
  • Observer-すばらしいパターン...コードの読み取りとデバッグがはるかに難しくなります
  • Prototype-コンパイラーのダイナミズムをチェックします(良いか悪いかは異なります...)
  • Chain of responsibility-あまりにも頻繁に強制的に/人工的にデザインにプッシュされた

それらの「非実用的なもの」については、それらを使用する前に本当に考える必要があります。通常、どこかにもっとエレガントな解決策があるからです。

「把握しに​​くい」人にとっては...彼らは適切な場所で使用され、適切に実装されていると本当に助けになります...しかし、それらは不適切に使用されると悪夢です。

さて、次は….

6
Marcel Toth

私はこれに対してあまりbeatられないことを望みます。 Christer Ericssonは、彼の リアルタイム衝突検出ブログ でデザインパターンのトピックに関する2つの記事( onetwo )を書きました。彼の口調はかなり厳しく、おそらく少し挑発的ですが、その人は彼のものを知っているので、私は狂人の絶賛としてそれを却下しません。

5
falstro

service locator はアンチパターンであると言う人もいます。

5
Arnis Lapsa

オブザーバーパターンには多くの答えがあり、非常に一般的なケースで機能しますが、システムが複雑になると悪夢になり、OnBefore()、OnAfter()通知が必要になります。エンターシー。はるかに優れたソリューションは、計算中にすべてのオブジェクトアクセス(読み取りバリア付き)をインスツルメントし、依存関係グラフに自動的にエッジを作成する自動依存関係分析システムを開発することです。

2
Jesse Pepper

Spoikeの投稿を補完する パターンへのリファクタリング は良い読み物です。

2
Adeel Ansari

イテレータは、回避するためのもう1つのGoFパターンです。または、少なくとも代替手段がない場合にのみ使用します。

代替手段は次のとおりです。

  1. for-eachループ。この構造は、ほとんどの主流言語に存在し、ほとんどの場合、反復子を回避するために使用できます。

  2. lINQまたはjQueryのセレクター。コンテナのすべてのオブジェクトを処理する必要はないため、for-eachが適切でない場合に使用する必要があります。イテレータとは異なり、セレクタを使用すると、処理するオブジェクトの種類を1か所に明示できます。

0