web-dev-qa-db-ja.com

コンストラクタを分解するにはどうすればよいですか?

Enemyクラスがあり、コンストラクタは次のようになります。

public Enemy(String name, float width, float height, Vector2 position, 
             float speed, int maxHp, int attackDamage, int defense... etc.){}

コンストラクターには非常に多くのパラメーターがあるため、これは見栄えが悪いですが、Enemyインスタンスを作成するときは、これらすべてのものを指定する必要があります。また、Enemyクラスにこれらの属性が必要なため、それらのリストを反復処理してこれらのパラメーターを取得/設定できます。 EnemyをEnemyB、EnemyAにサブクラス化して、それらのmaxHpおよびその他の特定の属性をハードコーディングすることを考えていましたが、Enemy(EnemyA、EnemyB、およびEnemyC's)。

私はただきれいにコーディングする方法を学ぼうとしています。それが違いを生むなら、私はJava/C++/C#で作業します。正しい方向の任意の点が評価されます。

21
Travis

解決策は、パラメータを複合型にバンドルすることです。幅と高さは概念的に関連しています。これらは敵の寸法を指定し、通常は一緒に必要になります。それらはDimensionsタイプ、またはおそらく位置も含むRectangleタイプに置き換えることができます。一方、positionspeedMovementDataタイプにグループ化するほうが理にかなっている可能性があります。コンテキストから、maxHpattackDamagedefenseなどもStatsタイプに属していると想定します。したがって、修正された署名は次のようになります。

public Enemy(String name, Dimensions dimensions, MovementData movementData, Stats stats)

どこに線を引くかは、コードの残りの部分と、一緒に使用されるデータによって異なります。

58
Doval

Builderパターン を確認してください。リンクから(パターンと代替案の例付き):

[The] Builderパターンは、コンストラクターまたは静的ファクトリーが少数のパラメーターを超えるクラスを設計する場合、特にそれらのパラメーターのほとんどがオプションである場合に適しています。クライアントコードは、従来の伸縮コンストラクタパターンよりもビルダーを使用した方がはるかに読み書きが簡単で、ビルダーはJavaBeansよりもはるかに安全です。

24
Rory Hunter

サブクラスを使用して一部の値を事前設定することは望ましくありません。新しいタイプの敵が異なる動作または新しい属性を持っている場合のみサブクラス化します。

factory patternは通常、使用されるクラスを抽象化するために使用されますが、オブジェクト作成用のテンプレートを提供するためにも使用できます。

class EnemyFactory {

    // each of these methods is essentially a template for a kind of enemy

    Enemy enemyA(String name, ...) {
        return new Enemy(name, ..., presetValue, ...);
    }

    Enemy enemyB(String name, ...) {
        return new Enemy(name, ..., otherValue, ...);
    }

    Enemy enemyC(String name, ...) {
        return new EnemySubclass(name, ..., otherValue, ...);
    }

    ...
}

EnemyFactory factory = new EnemyFactory();
Enemy a = factory.enemyA("fred", ...);
Enemy b = factory.enemyB("willy", ...);
5
amon

Rory Hunterの回答に追加するコード例(Javaの場合):

public class Enemy{
   private String name;
   private float width;
   ...

   public static class Builder{
       private Enemy instance;

       public Builder(){
           this.instance = new Enemy();
       }


       public Builder withName(String name){
           instance.name = name;
           return this;
       }

       ...

       public Enemy build(){
           return instance;
       }
   }
}

これで、次のようにしてEnemyの新しいインスタンスを作成できます。

Enemy myEnemy = new Enemy.Builder().withName("John").withX(x).build();
0
Toon Borgers

個別に使用する可能性のあるオブジェクトを表すクラスへのサブクラス化を予約します。敵だけでなくすべての文字に名前、速度、maxHp、または幅、高さ、位置を持つ画面上に存在するスプライトを表すクラスがある文字クラス。

多くの入力パラメーターを持つコンストラクターには本質的に問題はありませんが、少し分割したい場合は、ほとんどのパラメーターをセットアップする1つのコンストラクターと、使用できる別の(オーバーロードされた)コンストラクターを用意できます。特定のものを設定し、その他をデフォルト値に設定します。

使用する言語によっては、コンストラクターの入力パラメーターのデフォルト値を次のように設定できるものもあります。

Enemy(float height = 42, float width = 42);
0
Encaitar