タグ付けされた質問 「design-patterns」

設計パターンは、ソフトウェア設計で一般的に発生する問題に対する一般的な再利用可能なソリューションです。

4
「時期尚早の抽象化」とは何ですか?
私はフレーズが乱れているのを聞いたし、私には議論が完全に正気ではないように聞こえます(ここでわざわざ言っているとすみません、それは私の意図ではありません)。 一般的なケースがわかる前に抽象化を作成したくない場合は、(1)属していないものを抽象化に入れるか、(2)重要なものを省略します。 (1)私にはこれはプログラマーが十分に実用的ではないように聞こえます、彼らは最終的なプログラムには存在しないものがあると仮定しているので、抽象化のレベルが低い状態で作業していますが、問題はありません時期尚早な抽象化、それは時期尚早な結着です。 (2)重要なことの省略は1つです。後で重要になることが仕様から省略されている可能性があります。これに対する解決策は、独自の結論を導き出してリソースを無駄にすることではありません。間違っていると思います、それはクライアントからより多くの情報を取得することです。 これは、抽象化から具体化に至るまで常に作業する必要があります。これは、最も実用的な方法であり、その逆ではないためです。 そうしないと、クライアントを誤解し、変更が必要なものを作成するリスクがありますが、クライアントが独自の言語で定義した抽象化のみを構築する場合は、このリスクにぶつかることはありません(少なくとも、いくつかの具体的な暗闇の中でのショット)、はい、クライアントは詳細について考えを変える可能性がありますが、本来彼らが望むものを伝えるために使用していた抽象化は依然として有効である傾向があります。 以下に例を示します。クライアントがアイテムバギングロボットの作成を希望しているとします。 public abstract class BaggingRobot() { private Collection<Item> items; public abstract void bag(Item item); } 私たちは、クライアントが使用した抽象化から何かを構築していますが、わからないことについては詳しく説明していません。これは非常に柔軟性があり、「時期尚早な抽象化」と呼ばれるのを見てきましたが、実際にはバギングがどのように実装されたかを想定するのは時期尚早です。複数のアイテムを一度にバギングすることをクライアントと話し合った後、 。クラスを更新するために必要なのはシグネチャを変更することだけですが、ボトムアップを始めた人にとっては、大規模なシステムのオーバーホールが必要になる可能性があります。 時期尚早な抽象化などはなく、時期尚早な結集だけです。このステートメントの何が問題になっていますか?私の推論のどこに欠陥がありますか?ありがとう。

2
警告システムのアーキテクチャ
さまざまなプログラムからのアラートメッセージを処理し、それらのアラートを処理して電子メールを介してダウンコンシューマーに送信できるシステムを作成したいと考えています。これはすべて1つの内部ネットワークに含まれます。 基本的なアーキテクチャを次のようにしたいと思います。 私の現在の主な関心事は「メッセージハンドラー」ビットです。これが私の「ソートAPI」になります。このシステムのすべてのコンポーネントが、データベースへのすべての書き込みを処理するAPIにデータを送信するようにします。このアプローチは、セキュリティを簡素化し、より複雑なDBクエリの多くを1つのプログラムに含めることができるため、より簡単だと思います。 懸念事項は、これを言語にとらわれないようにしたいことです。つまり、どのコードでもメッセージをハンドラに送信して、メッセージを解釈できるようにする必要があります。これは、JSONフラットファイルを介して、またはプログラムへのREST呼び出しを介して(下流のアプリケーションに柔軟性を与える)希望します。 私の質問は メッセージハンドラーを気にする必要がありますか?それとも、下流のアプリケーションと他の2つのコンポーネント(管理コンソールとアラートマネージャー)への直接データベースアクセスを許可するだけで簡単になりますか? このようにして、DBテーブルへのINSERTが有効である限り、任意のアラートを挿入できます。 私は貿易でソフトウェアデザイナーではないので、失礼します。ただ、自由な時間にプロジェクトをやってもらいたいのです。

5
類似した機能に異なるパターンを使用する
私はプロジェクトの唯一の開発者です。これは、他のソフトウェアプロジェクトと同様に、将来誰かに奪われる可能性があります。 機能Aを実装するためにパターンXを使用したとしましょう。機能を開発して完成させた後、今学んだパターンYを使用して同じ機能を実装できることに気付きました。しかし、機能Aはうまく機能しており、XからYへのリファクタリングは時間がかかり、ほとんどメリットがありません。 次に、機能Bを実装します。これはAに似ていますが、今回はこの機会にパターンYで遊んでみたいと思います。機能Aを実行するときよりも、最終結果に満足しています。ただし、コードでは2つ使用していますXとYの異なるパターン。 ただし、機能AIを構築するときに機能Bと同じパターンを使用するのに十分なスキルがなかったという事実を除いて、異なるパターンを使用する実際の理由はありません。 この質問は、特定の問題に適切なパターンを選択することに関するものではないことに注意してください。同様の問題を解決するためにコードベースに共存する約2つのパターンは、リファクタリングするのに十分な時間を与えると1つに減らすことができます。 そのコードは臭いですか? このようにソースコードを保持することの欠点は何ですか? 1つのパターンのみを使用する必要がありますか?つまり、Bを記述するときに、AをリファクタリングしてYを使用するか、Xを使用し続けるか。 ソースで、類似した機能に2つの異なるパターンがある理由は本質的に理由がないことをどのように伝えることができますか? 次の開発者が私のコードをどう思うかについてあまり心配していませんか?

3
疎結合コードのインターフェースの使用
バックグラウンド 特定の種類のハードウェアデバイスの使用状況に依存するプロジェクトがありますが、必要なことを行うのであれば、誰がそのハードウェアデバイスを作成するかは重要ではありません。そうは言っても、同じことをするはずの2つのデバイスでも、同じ製造元以外のデバイスでは違いがあります。したがって、インターフェイスを使用して、関連するデバイスの特定のメーカー/モデルからアプリケーションを分離し、代わりに、インターフェイスに最高レベルの機能をカバーさせることを考えています。これが私のアーキテクチャが次のようになると私が考えているものです: 1つのC#プロジェクトでインターフェイスを定義しますIDevice。 別のC#プロジェクトで定義されたライブラリに、デバイスを表すために使用される具象があります。 具体的なデバイスにIDeviceインターフェースを実装してもらいます。 IDeviceインタフェースは次のような方法かもしれないGetMeasurementかをSetRange。 アプリケーションに具象に関する知識を持たせ、具象をデバイスを利用する(実装しない)アプリケーションコードに渡しIDeviceます。 アプリケーションに影響を与えずに、使用中のデバイスを変更できるため(これは時々発生するようです)、これが適切な方法であると確信しています。言い換えると、具象の実装方法GetMeasurementやSetRange具象を通して実際に機能する方法は重要ではありません(デバイスのメーカーによって異なる場合があります)。 私の心の中で唯一の疑問は、今やアプリケーションとデバイスの具象クラスの両方がIDeviceインターフェースを含むライブラリに依存しているということです。しかし、それは悪いことですか? また、デバイスとIDevice同じ名前空間に属していない限り、アプリケーションがデバイスについて知る必要がない方法もわかりません。 質問 これは、アプリケーションとそれが使用するデバイスとの間の依存関係を切り離すためのインターフェースを実装するための正しいアプローチのように思えますか?

5
戦略パターンと依存性注入を使用して継承を完全に置き換えることはできますか?
例えば: var duckBehaviors = new Duckbehavior(); duckBehaviors.quackBehavior = new Quack(); duckBehaviors.flyBehavior = new FlyWithWings(); Duck mallardDuck = new Duck(DuckTypes.MallardDuck, duckBehaviors) Duckクラスにはすべての動作(抽象)が含まれているため、新しいクラスMallardDuck(拡張Duck)を作成する必要はないようです。 参照:ヘッドファーストデザインパターン、第1章。

6
依存性注入の最良の定義は何ですか?
誰かが私に連絡して、依存性注入を概念的な方法で定義し、ソフトウェア設計でDIを使用することの実際の長所と短所を説明するように求められるたびに。DIの概念を説明するのが難しいと告白します。単一の責任の原則、継承に関する構成などに関する歴史を伝える必要があるたびに。 開発者のためにDIを説明する最良の方法を説明してくれる人はいますか?

6
同様に最適化されていない設計を繰り返し繰り返すことをどのように回避しますか?
おそらく多くの人と同じように、設計の問題が頭痛の種になっていることがよくあります。たとえば、問題に直感的に適合し、望ましい利点があるデザインパターン/アプローチがあります。多くの場合、何らかの回避策がないとパターン/アプローチを実装するのが困難になる警告があり、パターン/アプローチの利点が無効になります。多くのパターン/アプローチを繰り返し処理してしまう可能性があります。実際には、簡単な解決策がない実際の状況では、ほぼすべてのパターンに非常に大きな注意事項があるためです。 例: 最近遭遇した実際のものに大まかに基づいた架空の例を紹介します。継承階層が過去のコードのスケーラビリティを妨げていたため、継承ではなくコンポジションを使用したいとしましょう。私はコードをリファクタリングするかもしれませんが、スーパークラス/ベースクラスがサブクラスの機能を単に呼び出す必要があるにもかかわらず、それを回避しようとするいくつかのコンテキストがあることがわかりました。 次善のアプローチは、半分のデリゲート/オブザーバーパターンと半分の構成パターンを実装して、スーパークラスが動作を委任できるようにするか、サブクラスがスーパークラスのイベントを監視できるようにすることです。その場合、クラスを拡張する方法が不明確であるため、クラスの拡張性と保守性が低下します。また、既存のリスナー/デリゲートを拡張するのも難しいです。また、スーパークラスを拡張する方法を確認するために実装を知る必要があるため、情報は十分に隠されていません(コメントを非常に広範囲に使用しない限り)。 したがって、この後は、オブザーバーまたはデリゲートを完全に使用して、アプローチを過度に混同することに伴う欠点を回避することを選択する場合があります。ただし、これには独自の問題があります。たとえば、事実上すべての行動にオブザーバー/デリゲートが必要になるまで、行動の量を増やすためにオブザーバーまたはデリゲートが必要になることに気づく場合があります。1つのオプションは、すべての動作に対して1つの大きなリスナー/デリゲートを持つことですが、実装するクラスは多くの空のメソッドなどで終了します。 それから私は別のアプローチを試すかもしれませんが、それと同じくらい多くの問題があります。それから次のもの、そして次のものなど。 この反復プロセスは、各アプローチが他のアプローチと同じくらい多くの問題を抱えているように見え、一種の設計決定麻痺につながる場合、非常に難しくなります。また、使用する設計パターンやアプローチに関係なく、コードが同じように問題を抱えてしまうことを受け入れるのも困難です。このような状況になった場合、問題自体を再検討する必要があるということですか。この状況に遭遇したとき、他の人は何をしますか? 編集: 私が明確にしたい質問のいくつかの解釈があるようです: OOPは実際にはOOPに固有のものではないことが判明したため、OOPについて質問から完全に除外しました。さらに、OOPについて渡した私のコメントの一部を誤解するのは簡単です。 反復的なアプローチでさまざまなパターンを試す必要があると主張したり、パターンが機能しなくなった場合は破棄したりする必要があると主張する人もいます。これは私が最初に参照するつもりだったプロセスです。これは例からは明らかだと思いましたが、もっと明確にすることができたので、そのために質問を編集しました。

4
コンパイラは型エラーからどの程度正確に回復しますか?
私はいくつかの論文、記事、およびコンパイラー:原則、手法、およびツール(第2版)(別名「ドラゴン・ブック」)のセクション4.1.4、第4章を読み、すべて構文コンパイラーのエラー回復のトピックについて説明しています。ただし、いくつかの最新のコンパイラーで実験した後、構文エラーだけでなく、セマンティックエラーからも回復することがわかりました。 構文的に関連するエラーから回復するコンパイラーの背後にあるアルゴリズムと手法はかなりよく理解していますが、コンパイラーがセマンティックエラーから回復する方法を正確には理解していません。 現在、ビジターパターンのわずかなバリエーションを使用して、抽象構文ツリーからコードを生成しています。コンパイラが次の式をコンパイルすることを検討してください。 1 / (2 * (3 + "4")) コンパイラーは、次の抽象構文ツリーを生成します。 op(/) | ------- / \ int(1) op(*) | ------- / \ int(2) op(+) | ------- / \ int(3) str(4) コード生成フェーズでは、ビジターパターンを使用して、抽象構文ツリーを再帰的に走査し、型チェックを実行します。コンパイラが式の最も内側の部分に到達するまで、抽象構文ツリーをたどります。(3 + "4")。次に、コンパイラーは式の両側をチェックし、それらが意味的に同等ではないことを確認します。コンパイラは型エラーを発生させます。ここに問題があります。今コンパイラは何をすべきですか? コンパイラは、このエラーから回復し、式の外側の部分を型チェックを継続するためには、返却しなければならないいくつかのタイプ(intまたはstrに、表現の最も内側の部分を評価するから)を、次式の最も内側の部分。ただし、単に返すタイプがありません。型エラーが発生したため、型は推定されませんでした。 私が仮定した1つの可能な解決策は、型エラーが発生した場合、エラーが発生し、型エラーが発生したことを示す特別な値が以前の抽象構文ツリートラバーサル呼び出しに返されることです。以前のトラバーサル呼び出しでこの値が検出された場合、抽象構文ツリーのより深いところで型エラーが発生したことがわかっているため、型を推測することは避けてください。この方法は機能するように見えますが、非常に非効率的です。式の最も内側の部分が抽象構文ツリーの奥にある場合、コンパイラーは多くの再帰呼び出しを行って、実際の作業が実行できないことを認識し、それぞれから単に戻る必要があります。 上記の方法を使用していますか(疑わしい)。もしそうなら、それは効率的ではありませんか?そうでない場合、コンパイラがセマンティックエラーから回復するときに使用される方法は正確には何ですか?

5
LSPに違反しても大丈夫ですか?
私はこの質問についてフォローアップしていますが、コードから原則に焦点を移しています。 Liskov置換原理(LSP)についての私の理解から、私の基本クラスにあるメソッドは何でも、それらは私のサブクラスに実装する必要があります。このページによれば、基本クラスのメソッドをオーバーライドし、何も実行しないか、例外、あなたは原則に違反しています。 さて、私の問題は次のようにまとめることができます:私は抽象Weapon classと2つのクラス、Swordとを持っていReloadableます。と呼ばれるReloadable特定のが含まれている場合、それにアクセスするにはダウンキャストする必要があります。理想的には、それを回避する必要があります。methodReload()method 次に、を使用することを考えましたStrategy Pattern。このように、各武器は実行可能なアクションのみを認識していたため、たとえば、Reloadable武器は明らかにリロードSwordできますが、リロードすることはできませんReload class/method。Stack Overflowの投稿で述べたように、ダウンキャストする必要はなく、List<Weapon>コレクションを維持できます。 で別のフォーラム、最初の答えができるようにする提案Swordを認識するReloadだけで何もしません、。これと同じ答えが、上でリンクしたスタックオーバーフローのページにもありました。 理由はよくわかりません。なぜ原則に違反し、Swordにを認識さReloadせ、空白のままにするのですか?Stack Overflowの投稿で述べたように、SPで問題がほぼ解決しました。 なぜそれが実行可能な解決策ではないのですか? public final Weapon{ private final String name; private final int damage; private final List<AttackStrategy> validactions; private final List<Actions> standardActions; private Weapon(String name, int damage, List<AttackStrategy> standardActions, List<Actions> attacks) { this.name = name; this.damage = damage; standardActions = new …

4
Java:セッターの順序が重要ではないステップビルダーを実装する方法は?
編集:この質問は理論的な問題を説明していることを指摘したいと思います。必須パラメーターにコンストラクター引数を使用できること、またはAPIが正しく使用されていない場合はランタイム例外をスローできることを認識しています。ただし、コンストラクター引数やランタイムチェックを必要としないソリューションを探しています。 次のCarようなインターフェースがあるとします。 public interface Car { public Engine getEngine(); // required public Transmission getTransmission(); // required public Stereo getStereo(); // optional } コメントが示唆するCarように、Engineとは必須ですTransmissionが、Stereoはオプションです。つまりbuild()、Carインスタンスが可能なビルダーは、ビルダーインスタンスにとの両方が既に与えられているbuild()場合にのみメソッドEngineをTransmission持つ必要があります。その方法は、型チェッカーが試みが作成することは、任意のコードコンパイルを拒否しますCarせずにインスタンスEngineまたはTransmission。 これには、ステップビルダーが必要です。通常、次のようなものを実装します。 public interface Car { public Engine getEngine(); // required public Transmission getTransmission(); // required public Stereo getStereo(); // optional public class Builder { public BuilderWithEngine engine(Engine …

5
コンパイル時の値パラメーターを使用したJavaクラスの生成
クラスが同じ基本的な動作、メソッドなどを実装しているが、そのクラスの複数の異なるバージョンが異なる用途に存在する可能性がある状況を考えてみましょう。私の特定のケースでは、ベクトル(リストではなく幾何学的ベクトル)があり、そのベクトルは任意のN次元ユークリッド空間(1次元、2次元など)に適用できます。このクラス/タイプはどのように定義できますか? これは、クラステンプレートがパラメーターとして実際の値を持つことができるC ++では簡単ですが、Javaにはそのような贅沢はありません。 この問題を解決するために私が考えることができる2つのアプローチは次のとおりです。 コンパイル時に可能な各ケースの実装を持つ。 public interface Vector { public double magnitude(); } public class Vector1 implements Vector { public final double x; public Vector1(double x) { this.x = x; } @Override public double magnitude() { return x; } public double getX() { return x; } } public class Vector2 …

3
多くの引数を持つコンストラクターの回避
だから私は異なるクラスのオブジェクトを作成するファクトリーを持っています。可能なクラスはすべて抽象祖先から派生しています。ファクトリーには構成ファイル(JSON構文)があり、ユーザーの構成に応じて、作成するクラスを決定します。 これを実現するために、ファクトリはJSON解析にboost :: property_treeを使用します。彼はptreeをウォークスルーし、どの具象オブジェクトを作成するかを決定します。 ただし、製品オブジェクトには多くのフィールド(属性)があります。具体的なクラスにもよりますが、オブジェクトには約5〜10個の属性があり、将来的にはさらに増える可能性があります。 そのため、オブジェクトのコンストラクターがどのように見えるかわかりません。私は2つの解決策を考えることができます: 1)製品のコンストラクターはすべての属性をパラメーターとして想定しているため、コンストラクターは最終的に10個以上のパラメーターになります。これは醜く、長くて読めないコード行につながります。ただし、利点は、ファクトリーがJSONを解析し、正しいパラメーターでコンストラクターを呼び出すことができることです。製品クラスは、JSON構成のために作成されたことを知る必要はありません。JSONや設定が含まれていることを知る必要はありません。 2)製品のコンストラクターは、property_treeオブジェクトという1つの引数のみを想定しています。次に、必要な情報を解析できます。構成内の情報が欠落しているか範囲外の場合、各製品クラスは適切に対応できます。ファクトリは、いくつかの製品に必要な引数を知る必要はありません。ファクトリーは、誤った構成の場合の対応方法を知る必要もありません。また、コンストラクターインターフェイスは統一されており、小さいです。ただし、デメリットとして、製品は必要な情報をJSONから抽出する必要があるため、JSONがどのように構成されているかを認識しています。 私は解決策2)を好む傾向があります。ただし、これが適切なファクトリパターンであるかどうかはわかりません。JSON構成で作成されていることを製品に通知するのは、どういうわけか間違っていると感じます。一方、新製品は非常に簡単に導入できます。 それについての意見はありますか?

3
多対多の深い関係を管理するための設計パターンはありますか?
複数のアプリケーションで作業しているこのデータパターンを定義するのに問題があります。 それはで構成されています: 多くのオブジェクト自体で構成されるオブジェクトタイプ 2番目のオブジェクトタイプ。各インスタンスは最初のオブジェクトの「多く」を持っています また、最初のオブジェクトの各サブオブジェクトは、2番目のオブジェクトタイプへの関連付けごとに変更できます。 簡単な例は次のとおりです。 一連のレッスンで構成されるプログラミングコース レッスンはセットの割り当てで構成されています。 コースを学生に割り当てることができます。 ただし、コースが生徒に割り当てられると、各レッスンや課題は、削除や追加を行って、元のコースが認識できなくなる可能性があるまで、その生徒に合わせてカスタマイズできます。 私の解決策では、これにより次のような結果になります。 コースを生徒に割り当てると、コースはメモリにロードされます。次に、各サブオブジェクトについて、適切なメタデータを使用して生徒/サブオブジェクト関係オブジェクトが生成されます。基本的に、元のオブジェクトをテンプレートとして使用して、必要なカスタマイズ可能なオブジェクトを生成しています。 これにより、サブオブジェクトがより複雑になり、番号が付けられるため、大量のデータが生成されます。このデータパターンを操作するために必要なロジック/複雑さの量を減らすための最適化またはパターンがあるかどうかと思います。

4
構成を通じてインターフェースを実装するクラスのボイラープレートを削減する
:私はクラスの持っているA、小さなクラスの数の複合体であるB、CとD。 B、C、およびDインターフェースを実装IB、ICおよびIDそれぞれ。 以来Aのすべての機能をサポートB、CおよびD、A実装IB、ICおよびID同様に、しかし、多くのこの残念ながらリードの実装で再ルーティングA そのようです: interface IB { int Foo {get;} } public class B : IB { public int Foo {get {return 5;}} } interface IC { void Bar(); } public class C : IC { public void Bar() { } } interface ID { string Bash{get; set;} } public …

2
パッケージ(gems、eggなど)を使用して分離されたアーキテクチャを作成する
主な問題 最も近代的なプログラミングプラットフォームはパッケージ管理のために持っている良いサポートを見て(と思うgem、npm、pipなど、)、それが促進し、疎結合アーキテクチャを作成するように、内部で開発されたパッケージで構成されたアプリケーションやシステムを設計する意味がありませんか? 例 この例としては、データベースアクセス用のパッケージの作成や、システムの認証やその他のコンポーネント用のパッケージの作成があります。もちろん、これらも外部パッケージを使用します。次に、システムはこれらのパッケージをインポートして使用します-独自のコードベースにコードを含める代わりに。 考慮事項 私には、これはコードのデカップリングを促進し、保守性を支援するように思われます。ほとんどWebベースのデスクトップアプリケーションのようなものです(更新はほとんど自動的に適用され、単一のコードベースは単一の機能などに適用されます)。 これは合理的で健全なデザインコンセプトのように見えますか?これは、今日のアプリケーションを構造化する標準的な方法として実際に使用されていますか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.