Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice: instance variables filling over time

I'm new to the concept of object oriented programming (in java) and I often encounter the following design problem:

I often create classes with instance variables which are not known at the moment of initialization. These variables are filled over time. This is not a real problem since these variables are null until they are filled, my question therefore is more about the best practice in such situations.

Let me explain it with an example. I have a class Car. Every Car has a color, vMax, weight, horsepower etc.

When initializing the Car only it's color, weight and horsepower are known. --> Car(color, weight, horsepower)

The vMax can now be calculated (let's say: weight/horsepower). What confuses me is, that the Car, after initialization is "incomplete", meaning that the vMax will only be filled over time.

I found this quite ugly, and of course the car-example is simplified. I often have classes with 10+ properties where some are calculated over time, which themselves later in the code are used to calculate even more properties of that object. It then becomes difficult to know which variables are already filled at a certain point and which are not.

I just wondered whether this is "normal" and the way OOP works, or whether such situations should be avoided. If yes, I'd be glad for some design-hints.

Michael

like image 885
Fabian Gehring Avatar asked Apr 20 '15 10:04

Fabian Gehring


People also ask

How long do instance variables last?

Instance variables persist as long as there are variables referencing them. PHP internally stores a reference count on each object. When an variable goes out of scope, PHP decrements the refcount and checks for 0. If it's 0, it cleans up the instance and destroys the object.

Why are instance variables bad?

Because they are unnecessary but they will still float around in your views. The catch is, you know that they are unnecessary so you won't care about them (even if they contain wrong data) but next developers won't know that they are unnecessary.

What should instance variables be declared as?

Instance variables are declared without static keyword. Instance variables can be used only via object reference. Class variables can be used through either class name or object reference.

Which of the following is the lifetime of an instance variable?

The lifetime of an instance variable is until the object stays in memory.


2 Answers

As you define vMax should be a method more than an attribute of the class:

class Car {
    private String color;
    private double weight;
    private double horsePower;

    // constructor for Car
    public Car (String color, double weight, double horsePower) {
        this.color = color;
        this.weight= weight;
        this.horsePower= horsePower;
    }

    // usually I would create this as one-line-method...  but to clarify:
    public double getVMax() {
        double vMax = weight / horsePower; // calculate vMax!!!
        return vMax;
    }
}
like image 73
Jordi Castilla Avatar answered Sep 21 '22 20:09

Jordi Castilla


It all depends on what you need.

The very first thing that comes to my mind is to use builder (especially taken into account that you mentioned "classes with 10+ properties")

The main idea of the builder is you don't create an object, until you know/calculate all its properties.

Let's get back to your car example.

class Car
{
    final int weight;
    final int horsepower;
    final int vMax;
    final String color;

    private Car(int weight, int horsepower, int vMax, String color)
    {
        this.weight = assetNotNull(weight);
        this.horsepower = assetNotNull(horsepower);
        this.vMax = assetNotNull(vMax);
        this.color = assetNotNull(color);
    }

    //..... other car-related methods

    /** Car builder */
    public static class Builder
    {
        int weight;
        int horsepower;
        int vMax;
        String color;

        public Builder setWeight(int weight)
        {
            this.weight = weight;
            return this;
        }

        public Builder setHorsepower(int horsepower)
        {
            this.horsepower = horsepower;
            return this;
        }

        public Builder setvMax(int vMax)
        {
            this.vMax = vMax;
            return this;
        }

        public Builder setColor(String color)
        {
            this.color = color;
            return this;
        }

        public Car createCar()
        {
            return new Car(weight, horsepower, vMax, color)
        }
    }
}

Then you can build your car like this

Car.Builder builder = new Car.Builder();
Car car = builder.setColor("blue")
            .setHorsepower(10)
            .setvMax(100)
            .setWeight(1000)
            .createCar();

This approach has the next benefits:

  • Car object is built when all required fields are set. If you need additional validation, you can add it to the createCar() method
  • You can pass Builder objects between different methods to fill in the fields.
  • Whenever you have a Car object, you are confident that it's valid (it cannot be instantiated otherwise)
  • your Car object is thread safe :)

Hope that helps.

like image 37
Maks Avatar answered Sep 20 '22 20:09

Maks