2
\$\begingroup\$

The fact is that a material object must have a field that does not make sense to an immaterial object

Here is a class whose objects I want to divide into material and immaterial:

public class GameObject {
    protected boolean isHidden;
    protected Coordinate position;
    protected int pictureWidth, pictureHeight;
    public Object filling;

    protected GameObject(int pictureWidth, int pictureHeight, Coordinate position, boolean isHidden, Color filling){
        this.position = position;
        this.pictureWidth = pictureWidth;
        this.pictureHeight = pictureHeight;
        this.isHidden = isHidden;
        this.filling = filling;
    }

    protected GameObject(Coordinate position, boolean isHidden, BufferedImage filling){
        this.position = position;
        this.pictureWidth = filling.getWidth();
        this.pictureHeight = filling.getHeight();
        this.isHidden = isHidden;
        this.filling = filling;
    }

    protected GameObject(GameObject gameObject) throws IOException{
        this.position = new Coordinate(gameObject.getPosition());
        this.pictureWidth = gameObject.getPictureWidth();
        this.pictureHeight = gameObject.getPictureHeight();
        this.isHidden = gameObject.isHidden();
        this.filling = gameObject.getFilling(); // передается ссылка
    }

    private GameObject getGameObject() { 
        return this;
    }
    public void paint(Graphics gr) throws IOException{
        if(filling instanceof BufferedImage) {
            gr.drawImage((Image) filling, position.getX(), position.getY(), null);
        }
        else if(filling instanceof Color) {
            gr.setColor((Color) filling);
            gr.fillRect(position.getX(), position.getY(), pictureWidth, pictureHeight);
        } else {
            System.err.println("programmer, you forgot to add a way to draw this object");
        }
    }
    Object getFilling() {
        return filling;
    }

    int getPictureWidth() {
        return pictureWidth;
    }
    int getPictureHeight() {
        return pictureHeight;
    }
    boolean isHidden() {
        return isHidden;
    }
    Coordinate getPosition() {
        return position;
    }
}

I suppose that you need to create 2 classes that inherit GameObject, and make the constructor of the GameObject class visible only for these two classes:

1) class MaterialGameObject:

 public class MaterialGameObject extends GameObject{
    final int materialHeight;

    public MaterialGameObject(int materialHeight, int pictureWidth, int pictureHeight, Coordinate position, boolean isHidden, Color filling){
        super(pictureWidth, pictureHeight, position, isHidden, filling);
        this.materialHeight = materialHeight;
    }

    public MaterialGameObject(int materialHeight, Coordinate position, boolean isHidden, BufferedImage filling){
        super(position, isHidden, filling);
        this.materialHeight = materialHeight;
    }

    public MaterialGameObject(MaterialGameObject materialGameObject) throws IOException{
        super(materialGameObject.getGameObject());
        this.materialHeight = materialGameObject.getMaterialHeight();
    }

    public int getMaterialHeight() {
        return materialHeight;
    }

}

class ImMaterialGameObject:

public class ImMaterialGameObject extends GameObject{

    public ImMaterialGameObject(int pictureWidth, int pictureHeight, int materialHeight, Coordinate position, boolean isHidden, Color filling){
        super(pictureWidth, pictureHeight, position, isHidden, filling);
    }

    public ImMaterialGameObject(Coordinate position, boolean isHidden, BufferedImage filling){
        super(position, isHidden, filling);
    }

    public ImMaterialGameObject(GameObject gameObject) throws IOException{
        super(gameObject);
    }

}

Do you know a better way to solve the problem?

\$\endgroup\$
  • \$\begingroup\$ It's hard to offer alternatives to your problem without knowing what this is used for exactly. Could you provide an example of these GameObjects in use? \$\endgroup\$ – dustytrash Nov 16 '19 at 21:00
1
\$\begingroup\$

getGameObject - Never used. You should remove it. You can always use this, no need to have a function. If you meant for this to be protected, still remove it. Again use the object, no need to have a function.

ImMaterialGameObject - Unless "Im" stands for something, Immaterial is one word.

public Object filling; - You've obviously noticed all classes in Java extend from Object. Taking advantage of this is hackey. Instead you could use 2 separate fields and check if one or the other is null.

Onto the question "Is there a better approach?"

Without knowing what you're using this for, I'd say there's nothing wrong with your approach. To make things more clear, set GameObject to abstract.

\$\endgroup\$
  • \$\begingroup\$ yes, i agree, it should be moved to GameObject. The fact is that the class material gameObject contains a field that an immaterial gameObject should not have. That is why I create the class material gameObject. U cannot use empty class - "Implicit super constructor GameObject() is undefined for default constructor. Must define an explicit constructor" \$\endgroup\$ – Miron says reinstate Red Star Nov 16 '19 at 17:20
  • \$\begingroup\$ @Miron you would have to change the GameObject's constructor to public. You may also need to define a default constructor as your error message suggests. (A constructor with no arguments) \$\endgroup\$ – dustytrash Nov 16 '19 at 18:07
  • \$\begingroup\$ no, I want to prohibit the creation of an instance of the GameObject, since I already have a division that takes into account all the options (material, immaterial). In any case - why did we then create class constructors if we do not call them from a subclass? Creating an empty object should be prohibited, since the object must have coordinates, its own way of rendering. \$\endgroup\$ – Miron says reinstate Red Star Nov 16 '19 at 19:31
  • \$\begingroup\$ @Miron I've updated my answer. \$\endgroup\$ – dustytrash Nov 16 '19 at 21:16
  • \$\begingroup\$ 1) Yes, useful note. I did like this: super(materialGameObject); because MaterialGameObject is a subclass of GameObject. 2) it is "Immaterial". 3) But if the number of rendering methods increases greatly? Will you multiply entities? In any case, an undeclared variable cannot get into the object, and if it does, then we throw an error when trying to draw. 4) i agree, the abstractness of a class fully describes its essence and satisfies my needs. \$\endgroup\$ – Miron says reinstate Red Star Nov 17 '19 at 5:22
0
\$\begingroup\$

Naming

I assume that you are program a game which has multiple instances of GameObject.

Imagine we are program a chess game:
There are two players which play on a board with multiple pieces on it.
Since Chess is the context, I don't need to prefix all words with Chess: Chessplayer, Chessboard and Chesspiece.

Now to your scenario:
Since the context is a Game the prefix Game in GameObject is redundant.

To Generell

public class GameObject {

 // ...
 public Object filling;

 // ...

 public void paint(Graphics gr) throws IOException{
     if(filling instanceof BufferedImage) {
         gr.drawImage((Image) filling, position.getX(), position.getY(), null);
     }
     else if(filling instanceof Color) {
         gr.setColor((Color) filling);
         gr.fillRect(position.getX(), position.getY(), pictureWidth, pictureHeight);
     } else {
         System.err.println("programmer, you forgot to add a way to draw this object");
     }
 }

 // ...
}

The Object filling is to generell. We should create an abstract DrawTechnique which separate te:

public class GameObject {

  // ...
  public Drawable drawable;

  // ...

  public void paint(Graphics gr) throws IOException {
    drawable.drawOn(gr);
  }

  // ...
}

class Image implements Drawable {

  /*...*/

  @Override
  public void drawOn(Graphics gr) { /*...*/ }

}

class Color implements Drawable {

  /*...*/

  @Override
  public void drawOn(Graphics gr) { /*...*/ }

}

By using polymorphism you achieve a more flexible way: We don't need if-branches, is more type-save, we can add a new Drawable-type without modifying GameObject. Without polymorphism we need to add a new if-branch to check if it is a type we want to draw.

\$\endgroup\$
  • \$\begingroup\$ the fact is that the number of parameters for the fill method is different. So the interface cannot be used. for example, a BufferedImage should not use width and height for rendering. \$\endgroup\$ – Miron says reinstate Red Star Nov 18 '19 at 10:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.