蛇とはしご ゲームをデザインしました。私は妥当な量のクラスに分割し、OOP設計に関しては良い仕事をしたと思います。
しかし、私がデザインに対して下した決定について1つ質問があります。 Config
というクラスがあります。このクラスには、ウィンドウの解像度、プレーヤーの数、ゲーム内のヘビとはしごの数、グリッドなどに関する一連のグローバル変数が含まれています。クラスは現在、次のようになっています。
package com.company.app;
import Java.awt.*;
public class Config {
public static final int WINDOW_WIDTH = 900;
public static final int WINDOW_HEIGHT = 900;
public static final int ROWS = 10;
public static final int COLS = 10;
public static final int X_RESOLUTION = WINDOW_WIDTH / COLS;
public static final int Y_RESOLUTION = WINDOW_HEIGHT / ROWS;
public static final int NUMBER_OF_PLAYERS = 3;
public static final int PLAYER_WIDTH = 40;
public static final int xOffset = Config.X_RESOLUTION / 2 - 8;
public static final int yOffset = Config.Y_RESOLUTION / 2 + 10;
public static final int NUM_LADDERS = 5;
public static final int NUM_SNAKES = 5;
public static Color[] playerColors = {Color.red,Color.cyan,Color.yellow};
}
}
ユーザーオプションインターフェイスを追加して、ユーザーが難易度(ヘビやはしごの数を増やす/減らす)、プレーヤーの数などを選択できるようにしたいので、変数をstatic
に変更するだけで、 final
ユーザーが自分の設定を選択できるようにします。
このデザインが悪いか、拡張性がないと思いますか?これをどのように改善しますか、あるいは、この設計を何に置き換えますか?
ご覧になりたい場合は、プロジェクトが GitHub にアップロードされます。まだ完成していないのでバグがあります。
デザイン自体が本質的に「良い」または「悪い」ということは決してありません。これらの属性は、コンテキストなしでは適切に適用できません。優れた設計とは、プログラムを最も簡単な方法で非機能要件に適合させる設計です。そして時々グローバル変数はまさにこれです:コンテキストにうまくフィットする最も単純なソリューションです。
それで、あなたが自問する必要がある質問は、あなたの目的のためにデザインは十分であるか、または「十分にスケーラブル」ですか?
同じプロセス内で、異なるプレーヤーグループで複数のスレッドを実行するつもりですか?次に、プレーヤーの数または難易度に対して複数のグローバル変数が必要であることは明らかです。それが目的である場合、グローバルの使用はおそらく十分にスケーラブルではありません。
これらのグローバルのために、単体テストの記述に問題がありますか?テストがこれらのグローバルのいくつかに依存していて、それらの変数に異なる値を必要とするさまざまなテストがあり、実行の順序が異なると、これらのグローバルを通じて望ましくない副作用が発生する可能性があります。その場合、グローバルを使用することはもはや適切ではありません。
プログラムを数年にわたって保守および拡張することを計画しているため、これらのグローバルのために、保守の問題が発生すると予想しますか?多分、それらのグローバルがコードを作成し、他の人にとって理解するのが難しい方法のためでしょうか?次に、グローバル変数は間違ったツールです。
しかし、これらすべての質問に対する答えが「いいえ」である場合、これは単なる学習プログラムであるため、現時点ではグローバルを使用し、最初の問題が発生したときに後でリファクタリングしても問題ありません。プログラムを十分に維持するようにしてくださいDRY=なので、後でグローバル変数を非グローバル変数に置き換えることを決定するときに500桁を変更する必要はありません。
@DocBrownの回答に加えて。
Q:このデザインは悪い、またはスケーラブルではないと思いますか?これをどのように改善しますか、あるいは、このデザインを何に置き換えますか?
特定のクラスで定数を見つけること自体は悪くありません。非常に同じレベルの抽象化で、非常に同じクラスのすべての定数をクラスター化すると、問題が発生する可能性があります。 1
私は主に3つのことを考慮します:
クラスをfinalにして、誰もConfig
から拡張できないようにします。定数にアクセスするために、すべてのクラスがこの種のクラスを拡張(または実装)するのはひどいことです。ある時点で、そのようなクラスはOne Ring- "One Ringですべてを支配し、One Ringでそれらを見つけ、One Ringでそれらをもたらすすべて、そして暗闇の中でそれらをバインドします」。このような習慣は、コードの匂いが強いです。これは、(さまざまな抽象化レベルのあらゆる種類の)コンポーネントに、本来なら注入すべきデータへのアクセスを許可するためです。
抽象化のレベルに従って、これらのクラスをそれぞれの境界内の最上位レベルに移動することを検討してください。高いビジネスポリシー(抽象化)によってのみ到達可能にし、これらを低いレベル(コンクリートコンポーネント)に値を注入するようにします。定数へのアクセスをどこからでも無差別に許可しないでください。これらの定数の範囲を制御してください。逆はLocatorパターンと違いはありません。
スコープ|境界|レイヤー|懸念事項ごとに定数を分離します。 ViewConfig
、PersistenceConfig
、GameConfig
など.
1:定数は(通常)デフォルト値であり、すべてが同じレイヤーに属しているわけではなく、すべての単一モジュール|コンポーネントのスコープ内にある必要があります。
はい、それらのグローバルを使用したデザインは悪いです。コード内の他の多くの場所を壊さずにそれらを変更したり、それらを変数にしたりすることが難しいからです(密結合)。ポイントは、コードは変更に対して柔軟ではなく、現実の世界で作業する場合、変更は一般的であるということです。ソフトウェアですので、簡単に変更したいです。
ここにいくつかの設計フィードバックがあります:
無関係なデータを混同しています。なぜUIデータなのかWINDOW_WIDTHとWINDOW_HEIGHTはNUMBER_OF_PLAYERSと同じクラスに属していますか?
WINDOW_WIDTHはピクセル単位ですか? //名前をWINDOW_WIDTH_IN_PIXELSに変更します。変更する場合は、WINDOW_WIDTHを使用しているユーザーによって異なります。
UIクラスは、ゲームロジッククラスから分離する必要があります。だから私はUIを切り替えることができましたテキストベースからguiベースなので、UIデータは、たとえ今のところ一定であっても、UIクラスではプライベートメンバーである必要があります。ゲームデータ。プレイヤーの数は、ゲームのクラスでなければなりません。
他にご不明な点がありましたらお知らせください。