Andrew
Andrew

Reputation: 23

Attribute should not be changed after creation

Given the question - "All game objects provide the ability for external code to obtain their size. However, they do not provide the ability to have their size changed once it is created."

If I have a parent class with private fields such as this GameObject class:

public abstract class GameObject {
     private int size;

     public void setSize(int size) {
          this.size = size;
     }
}

and a children classes such as

public class Dinosaur extends GameObject {
     public Dinosaur() {
           this.setSize(100);
     }
}

public class Jeep extends GameObject {
     public Jeep() {
          this.setSize(10);
     }
 }      

How do I ensure that the size is not changed after the object is created? I am confused because if I make the setter method for size private then I cannot set the size for each GameObject individually upon creation.

EDIT: Added second child class for clarity.

Upvotes: 2

Views: 1060

Answers (5)

scottb
scottb

Reputation: 10084

Given the question - "All game objects provide the ability for external code to obtain their size. However, they do not provide the ability to have their size changed once it is created."

The usual way that this is done is by having the constructor of the parent class accept a size argument. This argument sets the value of an immutable size field. Subclasses may easily access this value, but they are unable to change it once it has been set. This is the most object-oriented way in which to meet the listed requirements.

For example:

public abstract class GameObject {
    private final int size;

    public GameObject(int size) {
        this.size = size;
    }

    public int size() { return this.size; }
    :
    :
}

and a child class:

public class Dinosaur extends GameObject {

    public Dinosaur() {
        super(100);
    }
    :
    :
}

Although there is some discussion in this thread about how subclasses may dynamically change the size field, a better design would be to use an immutable design like the one presented here and have client code request a new object with a different size if needed (say, with a copyOf() method). Immutable designs have several advantages over mutable ones and are usually the way to go when planning value classes.

Upvotes: 0

user8107648
user8107648

Reputation:

They're a few things wrong with your code.

First if the class shouldn't have the ability to set the size after creation, why provide a setter in the first place?

Second, a subclass could override your setSize method in the abstract class and do whatever it wanted. If you want inheritance do this:

public abstract class GameObject {

    private final size;

    public GameObject(int size){
        this.size = size;
    }
}

public class Dinosaur extends GameObject {

    public Dinosaur(int size){
        super(size)
    }
}

No setter is provided and the size must be made available at construction time. If you want a method to do it, make the method final. Like this:

public final setSize(int size){
   this.size = size;
}

By making it final the subclasses have to except the method as it is, no overriding.

Another approach is, make this class immutable. You don't use setters, but you can have getters, and the class would be made final, so no subclassing.

public final Dinosaur {

   private final int size;

   pubilc Dinosaur(int size){
       this.size = size;
   }

   public int getSize(){
       return this.size;
   }
}

Upvotes: 1

Vasily Vlasov
Vasily Vlasov

Reputation: 3346

If you need to make the size variable unchangeable then you should use final modifier. There are 2 ways to set the value for this kind of variables: 1) constructor 2) inline. As long as you would like to have an option to set your custom value in the client code for each object, you should use constructor:

public abstract class GameObject {

     private final int size;

     public GameObject(int size) {
         this.size = size;
     }
}

public Dinosaur extends GameObject {

   pubilc Dinosaur(int size){
       super(size);
   }
}

There is no need in setter method in that case.

Upvotes: 2

arshajii
arshajii

Reputation: 129497

(Note: I'm assuming you meant to have Dinosaur extend GameObject.)

You could override the setSize() method and throw an exception:

public class Dinosaur extends GameObject {
    ...

    @Override
    public void setSize(int size) {
        throw new UnsupportedOperationException("can't change dinosaur size");
    }
}

Upvotes: 0

Bruno Peres
Bruno Peres

Reputation: 16365

size can be final and size value passed in the constructor. Also you do not need a setter. You can make only the necessary getter.

public abstract class GameObject {
    private final int size;

    public GameObject(int size) {
        this.size = size;
    }

     public int getSize() {
         return this.size;
     }
}

Upvotes: 1

Related Questions