web-dev-qa-db-ja.com

オブジェクトを初期化する場所

エンティティコンポーネントシステムアーキテクチャを使用するゲームの一部であるBallEntityクラスがあります。

このクラスには、そのクラスの属性に似た「コンポーネント」があります。
getComponentsメソッドでこのコンポーネントを作成して初期化します。このコンポーネントを作成するには、SpriteComponentのSprite(つまり、画像がそのボールを表す)、BodyComponentのBody、CameraFollowerComponentのカメラなどの他のオブジェクトが必要です。
これらのオブジェクトは、コンストラクターへの引数を介してクラスに到達します。

BallEntityを次のようにインスタンス化します。

        BallEntity ballEntity = new BallEntity(new Sprite(atlas.findRegion("ball")),rubeSceneHelper.getBody("ball"), camera, rubeSceneHelper);

私の質問は、これらのオブジェクト(またはどちら)をBallEntityのコンストラクターで初期化する必要があるのか​​、それともBallEntityをインスタンス化するクラス内で初期化する必要があるのか​​ということです。

public class BallEntity extends UserEntity {
    public static final float SCALE = 0.78f;
    private final RubeSceneHelper rubeSceneHelper;
    private ScaledSprite ballSprite;
    private Body ballBody;
    private Camera camera;

    public BallEntity(Sprite sprite, Body ballBody, Camera camera, RubeSceneHelper rubeSceneHelper) {
        this.ballSprite = ScaledSprite.create(Sprite, SCALE / Sprite.getHeight());
        this.ballBody = ballBody;
        this.camera = camera;
        this.rubeSceneHelper = rubeSceneHelper;
    }

    @Override
    public Array<Component> getComponents() {
        Array<Component> components = new Array<Component>();
        components.add(PositionComponent.newInstance());
        components.add(CameraFollowerComponent.newInstance(camera));
        components.add(SpriteComponent.newInstance(ballSprite.getSprite()));
        components.add(BodyComponent.newInstance(ballBody));
        components.add(BallContextComponent.newInstance());
        return components;
    }

    @Override
    public void init(Entity entity) {
        BodyComponent bodyComponent = entity.getComponent(BodyComponent.class);
        bodyComponent.setPosition(Vector2.Zero);

        Fixture ballFixture = rubeSceneHelper.getFixture(bodyComponent.getBody(), "ball");
        ballFixture.setUserData(new FixtureUserData(FixtureType.BALL, entity));
    }
}
4
alexpfx

現在表示している方法(「この方法でBallEntityをインスタンス化する」)は、コンストラクターを呼び出してBallEntityを作成する実装(コード)によって実行されています。

明確にするために、重要なのは、それを表示する方法で、BallEntityを作成するすべての場所(別々のクラスまたは同じクラス内の複数の場所)で、作成方法を再指定しているということです。新しいコンポーネントオブジェクト。言い換えると、これらのBallEntityが作成される場所に関係なく、適切なコンポーネントを識別して作成するのは呼び出し元(BallEntityの作成者)の仕事であると言っています。

BallEntityが作成される場所が1つしかない場合は、それほど心配する必要はありません。

コード内にBallEntityが作成される場所が複数あることが判明した場合は、それぞれが概念的に異なる方法で実行されているのか、概念的に同じ方法で実行されているのかを確認する必要があります。

概念的に同じ方法で作成されているコンポーネントの多くについて、DRY(Do n't Repeat Yourself)の原則を適用し、このコードを配置する場所を見つける必要があります。

頭に浮かぶ2つの選択肢があります。

(1)ご提案のとおり、BallEntityでは、BallEntityに追加の上位レベルのコンストラクターを配置することにより、atlasrubeSceneHelper、およびcameraをパラメーターとして使用し、上記のインスタンス化で提案したコードを使用して他のコンストラクターを呼び出します。 (元のコンストラクターもプライベートにするか、削除して1つだけにすることもできます。)

(2)ファクトリデザインパターンを使用します。これは、これと同じ共通コードを他のファクトリクラスに配置することを示しています。 BallEntity(の作成)のリクエストと実際に何をどのように作成するかを分離するためにここに示している以外の理由がある場合は、通常、ファクトリパターンを使用します。

たとえば、ファクトリパターンを使用すると、BallEntityのサブクラスを返すことも、シングルトン(デザインパターン)を返すことも、BallEntitysのプールを管理することもできます。あらゆる種類の基準に基づいてそれらを配ります。一方、コンストラクターを使用すると、毎回新しいBallEntityしか返すことができません。

(最後に、複数のクラスがそれぞれBallEntityをインスタンス化し、各クラスが複数の場所でBallEntityをインスタンス化することが判明した場合でも、各クラスはそれ自体の内部で概念的に同じですが、実行されますクラス間で概念的に異なる場合は、他の提案が適切であり、おそらく他の各クラスでそのコードを1回収集します。これは、DRY必要に応じて複数回。)

5
Erik Eidt