3

I'm working on a web game that has several different types of bricks so I decided to implement the factory pattern. The bricks are stored in a database (must have) and then build using the factory with the properties from the result set.

Factory:

public class BrickBuilder {

public Brick build(String type, int width, int height, String image) {
    Brick brick = null;

    switch (type) {
        case "energy":
            brick = new EnergyBrick(width, height, image);
            break;
        ...

    return brick;
}

Parent class:

public abstract class Brick {

// Properties

public Brick(String type, int width, int height, String image){
    this.type = type;
    this.width = width;
    this.height = height;
    this.image = image;
}

public abstract void construct(double x, double y, int hitCount);

Concrete implementation:

public class EnergyBrick extends Brick {

// Properties

public EnergyBrick(int width, int height, String image) {
    super("energy", width, height, image);
}

@Override
public void construct(int hitCount, double x, double y) {
    this.hitCount = hitCount;
    this.x = x;
    this.y = y;
}

SQL ResultSet to Brick used by getAll, getByName, ... in the repository

private Brick rsToBrick(ResultSet rs) throws SQLException {
    String type = rs.getString("name");
    int width = rs.getInt("width");
    int height = rs.getInt("height");
    String image = rs.getString("image");

    Brick brick = BUILDER.build(type, width, height, image);

    return brick;
}

Generate bricks

private void generateBricks() {
    List<Brick> databaseBricks = BrickRepositorySQL.getInstance().getAll();
    bricks = new ArrayList<>();

    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 14; j++) {
            chance = Math.floor(Math.random() * 5);
            if (chance == 4) {
                continue;
            }
            if (chance == 3 || chance == 2 || chance == 1) {
                // Create new concrete brick with tesame properties as in the array 
                x = j * 140;
                y = i * 80;
                brick.construct(x, y, 1);
                if (chance == 0) {
                    x = j * 140;
                    y = i * 80;
                    // Create new concrete brick with tesame properties as in the array 
                    brick.construct(x, y, 1);
                }
                bricks.add(brick);
            }
        }
    }
}

I have an ArrayList that has all the different types of bricks from the database. I would like to take one of the bricks out of this array, for example the EnergyBrick and then create a new EnergyBrick with the same properties and use the construct method on this brick to set the x and y coordinates with the hitCount.

Things I have tried:

databaseBricks.get(brickIndex) and then use the construct method on this brick, problem is that all the bricks have the same reference

repository.getByName("energy") works perfectly but takes way too long to query the database for each brick

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
josephzigler
  • 285
  • 3
  • 13
  • 1
    So what is your question? sounds like you need to query the db and cache the values? – Minh Kieu Nov 28 '17 at 08:50
  • 1
    `brick.construct(x, y, 1);` where is brick declared? BTW can't you use JPA or at least Hibernate and automap the bricks? – Andrea Ligios Nov 28 '17 at 08:59
  • DiscriminatorColumn, DiscriminatorValue, and you don't even need the factory method, the DAO method, or whatever: https://stackoverflow.com/questions/35872402/why-is-discriminatorcolumn-ignored-when-using-jointable – Andrea Ligios Nov 28 '17 at 09:02
  • 1
    @AndreaLigios I left the brick instantiation out in my code example, never used java persistence before but will definitely take a look at it! Thank you. – josephzigler Nov 28 '17 at 09:16

1 Answers1

3

You have constructed your database to contain all of the required data, but have not constructed it to support your query patterns.

If querying a specific brick, you should have an index on the fields that comprise a unique brick.

and then create a new EnergyBrick with the same properties and use the construct method on this brick to set the x and y coordinates with the hitCount.

So, use your factory. You created it to make the construction of new bricks easier. Use it!

Brick brick = getBrickToBeCopied();
Brick newBrick = BrickBuilder.build(brick.getName(), brick.getWidth(), brick.getHeight(), brick.getImage());
database.store(newBrick);

or if the width and height changed

Brick brick = getBrickToBeCopied();
Brick newBrick = BrickBuilder.build(brick.getName(), newWidth, newHeight, brick.getImage());
database.store(newBrick);

One thing I see that is confusing things, it seems that X and Y position get confused for width and height. If your database is storing the position, then add it to the Brick object and maintain it in the database. While both position and dimension both have (x, y) value pairs, they represent different things, and swapping them will not lead to the desired results.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • Thank you! Using the brick builder again in the generateBricks method solved the problem. The x and y values are not stored in the database as the new bricks array is send to the frontend in json. – josephzigler Nov 28 '17 at 09:20
  • @josephzigler glad to have helped. You built that `BrickBuilder` and you know it works, use it! :) I hope you got a laugh from the comment, because you really did a great job. Sometimes life is like that, you can't see the tree in front of you because the forest is in the way! :) – Edwin Buck Nov 28 '17 at 09:22