Java - 多个装饰器不起作用

Sho*_*ked 2 java virtual decorator

我正在尝试装饰器.我创建了一个Tank类和两个装饰器:DoubleGunTank(射击更强大)和FasterTank(驱动更快).他们来了:

public class Tank {
    public int shoot() {
        return 100;
    }

    public int drive() {
        return 10;
    }
}
public class FasterTank extends Tank {

    protected Tank fTank;

    public FasterTank(Tank tank) {
        fTank = tank;
    }

    public int drive() {
        return fTank.drive() * 2;
    }
}

public class DoubleGunTank extends Tank {

    protected Tank fTank;

    public DoubleGunTank(Tank tank) {
        fTank = tank;
    }
    public int shoot() {
        return fTank.shoot() * 2;
    }   
}
Run Code Online (Sandbox Code Playgroud)

我要做的是用双枪和超高速装饰一辆坦克.所以我这样做:

Tank czolg = new Tank();
czolg = new FasterTank(czolg);
czolg = new DoubleGunTank(czolg);
System.out.println("Shoot: "+czolg.shoot());
System.out.println("Drive: "+czolg.drive());
Run Code Online (Sandbox Code Playgroud)

但结果是:

Shoot: 200
Drive: 10
Run Code Online (Sandbox Code Playgroud)

似乎只有一个装饰器激活DoubleGunTank类中的两个方法.所以我的问题是:如何让坦克更有力地射击并同时加快速度?

Tom*_*icz 5

所有装饰器都需要覆盖所有装饰对象的方法:

class FasterTank extends Tank {

    protected Tank fTank;

    public FasterTank(Tank tank) {
        fTank = tank;
    }

    public int drive() {
        return fTank.drive() * 2;
    }

    //crucial!  
    public int shoot() {
        return fTank.shoot();
    }
}

class DoubleGunTank extends Tank {

    protected Tank fTank;

    public DoubleGunTank(Tank tank) {
        fTank = tank;
    }
    public int shoot() {
        return fTank.shoot() * 2;
    }

    //crucial!  
    public int drive() {
        return fTank.drive();
    }

}
Run Code Online (Sandbox Code Playgroud)

原因如下:当你有:

Tank czolg = new DoubleGunTank(new FasterTank(new Tank()));
Run Code Online (Sandbox Code Playgroud)

并且你调用czolg.drive()它实际上调用了一个DoubleGunTank类的方法- 这是继承而没有任何改变Tank.所以不是使用目标的装饰方法而是fTank调用未触及的方法DoubleGunTank.

请注意,您可以通过使用Tank界面来避免此类问题- 这将强制您始终装饰所有方法.此外,如果您的目标Tank类具有某种状态或在构造函数中执行某些操作,则每个装饰器(从它继承)将具有此状态重复并将在构造函数中调用相同的代码.

更新(OP自己建议):

或者您可以使用abstract TankDecorator如下课程:

abstract class TankDecorator extends Tank {
    protected final Tank fTank;

    protected TankDecorator(Tank fTank) {
        this.fTank = fTank;
    }

    @Override
    public int shoot() {
        return fTank.shoot();
    }

    @Override
    public int drive() {
        return fTank.drive();
    }
}

class FasterTank extends TankDecorator {

    public FasterTank(Tank tank) {
        super(tank);
    }

    public int drive() {
        return fTank.drive() * 2;
    }

}

class DoubleGunTank extends TankDecorator {

    public DoubleGunTank(Tank tank) {
        super(tank);
    }
    public int shoot() {
        return fTank.shoot() * 2;
    }

}
Run Code Online (Sandbox Code Playgroud)

我在使用代理时遇到了这个问题- 也通过继承我的类来利用装饰模式.基类构造函数被调用两次.请参阅:CGLIB代理方法调用构造函数两次?Spring AOP创建额外的bean.

  • 我打算写那个! (2认同)