0

戦略と複合パターンを使用する必要がある実践を完了しようとすると、実際に問題が発生します。表面によって動作が異なる車両のコレクションを作成しようとしています。ただし、これらの車両は、表面上で複数の動作をする可能性があります。たとえば、気象条件が雪と雨に設定されている場合、雪のドライブと雨のドライブを同時に行うことができます。

私にはAbstractVehicleというクラスがあり、CarとBoatの2つの具体的なサブクラスがあります。

次に、IBehaviourというインターフェイスがあります。このインターフェースの実装は、LandBehaviourとWaterBehaviour(複合パターンの最上位層)と呼ばれる2つの抽象クラスです。これらのそれぞれには、サブクラスのコレクションがあります。LandBehaviourのみに焦点を当て、そのサブクラスはSnowBehaviour、StandardBehaviour、およびLandAssemblyを含む他のいくつかです。

LandBehaviourにコンポジットの上位層のコードを配置するというアイデアでした。次に、各具象サブクラスには、コンポジットの追加、削除、およびリスト部分の空の実装があり、LandAssemblyクラスには、さまざまな動作を実際に組み合わせるために必要なコードが含まれています。

これは、たとえば、車がStandardBehaviourとSnowBehaviourの両方を同時に持つことができるという結果を生成することを目的としています。

大量のコードを投稿するのではなく(そしてたくさんのコードがあります)、実装しようとしている基本構造についてのフィードバックを期待していました。現在、nullポインターの例外などのエラーがいくつか発生しており、それらを修正するために長い時間を費やすのではなく、プロジェクトのレイアウトが最初から正しいかどうかを把握したいと思いました。

編集:コードの追加-nullポインター例外を生成します

これは私のAbstractVehicleクラスです:

public AbstractVehicle (IBehaviour behaviourIn) {
    behaviour = behaviourIn;
}

public void setBehaviour(IBehaviour ib) {
    behaviour = ib;
}

public IBehaviour getBehaviour() {
    return behaviour;
}

public void move() {
    behaviour.ensureCorrectBehaviour();
}

車のサブクラス:

public Car () {
    super(new StandardBehaviour());
}

IBehaviourインターフェース:

public interface IBehaviour {
    public void ensureCorrectBehaviour();
}

LandBehaviour抽象クラス:

public void ensureCorrectBehaviour() {
}

public ILandBehaviour () {
}

private ILandBehaviour landBehaviour;

public ILandBehaviour (ILandBehaviour landBehaviour) {
    this.landBehaviour = landBehaviour;
}

public ILandBehaviour getBehaviour() {
    return landBehaviour;
}

public abstract void addBehaviour(ILandBehaviour behaviour);
public abstract void removeBehaviour(ILandBehaviour behaviour);
public abstract ILandBehaviour[] getBehaviours();

具体的な動作サブクラス(RacingBehaviour)の例:

public RacingBehaviour(ILandBehaviour landBehaviour) {
    super(landBehaviour);
}

public RacingBehaviour() {}

@Override
public void ensureCorrectBehaviour() {
    System.out.println("Vehicle is racing.");
}

public void addBehaviour(ILandBehaviour behaviour) {}
public void removeBehaviour(ILandBehaviour behaviour) {}
public ILandBehaviour[] getBehaviours() {
    return null;
}

そして最後にLandAssemblyクラス:

public class LandAssembly extends ILandBehaviour {

private List<ILandBehaviour> behaviours;

public LandAssembly(ILandBehaviour landBehaviour) {
    super(landBehaviour);
    behaviours = new ArrayList<ILandBehaviour>();
}

public LandAssembly() {}

public void addBehaviour(ILandBehaviour behaviour) {
    behaviours.add(behaviour);
}

public void removeBehaviour(ILandBehaviour behaviour) {
    behaviours.remove(behaviour);
}

public ILandBehaviour[] getBehaviours() {
    return behaviours.toArray(new ILandBehaviour[behaviours.size()]);
}   
}

私はこのランナーを使用しています:

    AbstractVehicle aCar = new Car(120);
    aCar.move();

    ILandBehaviour snow = new SnowBehaviour();
    ILandBehaviour racing = new RacingBehaviour();
    ILandBehaviour as = new LandAssembly();
    as.addBehaviour(snow);
    as.addBehaviour(racing);

コンポジットを実装する前は、すべて問題ありませんでした。クライアントを使用して新しい車を作成し、そのmove()メソッドを呼び出してから、動作を変更し、move()を再度呼び出して、違いを確認することができました。ただし、複合パターンの実装にensureCorrectBehaviour()メソッドを残していることに気づいていますが、これは明らかに間違っています。また、これを行った後、Carコンストラクターの「新しい」部分が機能しなかったことも認識しています。動作ごとに空のコンストラクターを追加する必要がありました。

作成したコードに明白な問題が見られますが、それらを修正する方法がよくわかりません。

4

1 に答える 1

0

デザインパターンが気になる場合は、クラス図が非常に役立ちます。多くの機能があり、それらの機能をより高いレベルの抽象化(雪/陸/水など)にグループ化しますが、車両は1つの動作しか取りません。車両は複数の機能を備えている必要がありますか?(確かにあなたが言うようにそれはします)。

クラスに具体的に定義された戦略を含めることを検討してください。戦略の各実装は異なる場合があります。

public abstract class Bird
{
    protected BirdCallStrategy callStrat;
    protected FlyStrategy flyStrat;
}

public class Duck
{
    public Duck()
    {
        callStrat = new QuackStrategy();
        flyStrategy = new FlySouthForWinterStrategy(TimeOfYear);
    }
}

public class Chicken
{
    public Chicken()
    {
        callStrat = new CluckStrategy();
        flyStrat = new NoFlyStrategy();
    }
}

これは、戦略に明確な抽象化がある場合にうまく機能します。この場合FlyingBirdCalling互いに関係はありませんが、実行時の実装によって変化することが許可されています(クワッキング、チャーピングまたはフライング、フライングではないなど)。

ただし、サブタイピングせずにオンザフライでさまざまなインスタンスを作成する場合は、デコレータパターンを調べることをお勧めします。デコレータパターンを使用すると、実行時に「機能」の任意の組み合わせをインスタンスに適用できます。

したがって、次のようにインスタンス化されるオブジェクトになってしまう可能性があります。

Window decoratedWindow = new HorizontalScrollBarDecorator (
                new VerticalScrollBarDecorator(new SimpleWindow()));
于 2013-03-19T23:53:17.770 に答える