504 HW4

Zhen Gao
S01401440

Extensible

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pWggSOJV-1633068895352)(./uml.jpg)]
Use Factory Design Pattern to create Balls and Strategies.

Class MovingBall inherited Ball, adding strategy and name properties and fuctions that support moving.

Use Singleton Pattern for Strategies, Factories and BallWorldStore.

Use Observer Pattern to update balls location and change Switch balls strategies.

Use MVC Pattern for the whole Server.

Robust

If a user request a url that does not exist, the controller will redirect him to the home page.

notFound((req, res) -> {
            return "<html><body><h3>The request is not found.</h3>" +
                    "<a href=\"/\">Back to home page.</a></body></html>";
        });

degigned classes NullBall and NullStrategy to dealwith illegal input,
the NullBall has no behavior, only to deal with null pointer exception

public class NullBall extends MovingBall {

    /**
     * Constructor.
     *
     * @param loc      The location of the ball on the canvas
     * @param radius   The ball radius
     * @param vel      The ball velocity
     * @param color    The ball color
     * @param strategy
     */
    protected NullBall(Point loc, int radius, Point vel, String color, IUpdateStrategy strategy) {
        super(loc, radius, vel, color, strategy);
        this.setColor("white");
        if (!Objects.equals(this.strategy.getName(), "Null")) {
            this.strategy = NullStrategy.getOnly();
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        
    }

    @Override
    public void update() {
        
    }
}

and the NullStrategy has no behavior too.

public class NullStrategy implements IUpdateStrategy {
    static NullStrategy ONLY;

    /**
     * get the only instance.
     */
    public static NullStrategy getOnly() {
        if (ONLY == null) {
            ONLY = new NullStrategy();
        }
        return ONLY;
    }

    /**
     * Constructor.
     */
    private NullStrategy() {
    }

    @Override
    public String getName() {
        return "Null";
    }

    @Override
    public void updateState(Ball context) {

    }
}

in BallFactory, when the user want to create a ball of a type does not exist, it will create a NullBall.

 default :
                ball = new NullBall(loc,radius,vel,"white",fac.make("null"));

In StrategyFactory it is the same.

default : 
                strategy = NullStrategy.getOnly();

Unit Test

requesting ball type with loadBall creates expected ball

 @Test
    void testLoad(){
        DispatchAdapter dis = new DispatchAdapter();
        PropertyChangeListener[] pcls = dis.loadBall("horizontal", "type");
        MovingBall ball = (MovingBall) pcls[pcls.length-1];
        assertEquals("Moving",ball.getName());
        assertEquals("Horizontal",ball.getStrategy().getName());

        pcls = dis.loadBall("rotated", "type");
        ball = (RotatedBall) pcls[pcls.length-1];
        assertEquals("Rotated",ball.getName());
        assertEquals("Rotated",ball.getStrategy().getName());

        pcls = dis.loadBall("vertical", "type");
        ball = (MovingBall) pcls[pcls.length-1];
        assertEquals("Moving",ball.getName());
        assertEquals("Vertical", ball.getStrategy().getName());

        pcls = dis.loadBall("oblique", "type");
        ball = (MovingBall) pcls[pcls.length-1];
        assertEquals("Moving",ball.getName());
        assertEquals("Oblique", ball.getStrategy().getName());

        pcls = dis.loadBall("switch", "type");
        ball = (SwitchBall) pcls[pcls.length-1];
        assertEquals("Switch",ball.getName());
        assertEquals("Horizontal", ball.getStrategy().getName());

        pcls = dis.loadBall("wrongtype", "type");
        ball = (NullBall) pcls[pcls.length-1];
        assertEquals("Null",ball.getName());
        assertEquals("Null", ball.getStrategy().getName());
    }

an update (for each ball type) moves ball to expected location

@Test
    void testUpdate(){
        BallWorldStore bws = BallWorldStore.getOnly();
        BallWorldStore.setCanvasDims(new Point(800,800));
        BallFac bf = BallFac.getOnly();

        MovingBall ball = (MovingBall) bf.make("horizontal");
        Point loc = ball.getLocation();
        loc.x += ball.getVelocity().x;
        ball.update();
        assertEquals(loc, ball.getLocation());

        RotatedBall ball1 = (RotatedBall) bf.make("rotated");
        loc = ball1.getLocation();
        double theta = ball1.getVelocity().x * 0.3;
        theta *= (Math.PI / 180);
        int oldX = loc.x;
        int oldY = loc.y;
        double newX = ball1.center.x + (oldX-ball1.center.x)*Math.cos(theta) - (oldY-ball1.center.y)*Math.sin(theta);
        double newY = ball1.center.y + (oldX-ball1.center.x)*Math.sin(theta) + (oldY-ball1.center.y)*Math.cos(theta);
        loc = new Point((int)newX, (int)newY);
        ball1.update();
        assertEquals(loc, ball1.getLocation());

        ball = (MovingBall) bf.make("vertial");
        loc = ball.getLocation();
        loc.y += ball.getVelocity().y;
        ball.update();
        assertEquals(loc, ball.getLocation());

        ball = (MovingBall) bf.make("oblique");
        loc = ball.getLocation();
        loc.x += ball.getVelocity().x;
        loc.y += ball.getVelocity().y;
        ball.update();
        assertEquals(loc, ball.getLocation());

        SwitchBall ball2 = (SwitchBall) bf.make("switch");
        loc = ball2.getLocation();
        loc.x += ball2.getVelocity().x;
        ball.update();
        assertEquals(loc, ball2.getLocation());
        bws.switchStrategy("vertical");
        loc = ball2.getLocation();
        loc.y += ball2.getVelocity().y;
        ball.update();
        assertEquals(loc, ball2.getLocation());
        bws.switchStrategy("oblique");
        loc = ball2.getLocation();
        loc.x += ball2.getVelocity().x;
        loc.y += ball2.getVelocity().y;
        ball.update();
        assertEquals(loc, ball2.getLocation());

    }

adding a ball to the BallWorld increases the number of balls by 1

 @Test
    void testAdd(){
        BallWorldStore bws = BallWorldStore.getOnly();
        int size = bws.getBalls().length;
        bws.loadBall("wrongtype","type");
        int newsize = bws.getBalls().length;
        assertEquals(1, newsize-size);
    }

clearing the BallWorld sets the number of balls to 0

@Test
    void testRemove(){
        BallWorldStore bws = BallWorldStore.getOnly();
        for (int i = 0; i < 5; i++) {
            bws.loadBall("wrongtype","type");
        }
        int size = bws.getBalls().length;
        assertEquals(5, size);
        bws.removeBallsFromStore();
        size = bws.getBalls().length;
        assertEquals(0, size);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值