When to use instance variables vs parameters?

7

Assuming that a A class uses a B class (directly or through a C interface to decouple A from C ).

Making it clear that A and B are independent parts, ie , the relationship between the two classes is not composition or an obvious aggregation, but there is a "weak" A uses B (in this case, through the contract established by C ).

Consider the two examples (in Java):

Example 1 - C as Instance Variable :

public class A {
    private C c;

    // Não estou discutindo injeção através de construtores vs. getters and setters
    // Apenas assuma que 'c' foi inicializado de alguma maneira
    public A(C c) {
        this.c = c;
    }

    public metodo1() {
       // faz algo com c   
    }

    public metodo2() {
       // faz algo com c   
    }

    public metodo3() { 
      // não faz nada com c
    }
}

Example 2 - C as parameter :

public class A {

    public metodo1(C c) {
       // faz algo com c   
    }

    public metodo2(C c) {
       // faz algo com c   
    }

    public metodo3() { 
       // não faz nada com c
    }
}

My question is what should I do with A having an instance variable of type C vs. when I should pass an instance of type C as a parameter to the methods of A ?

In other words: In what situations would the API exposed in Example 1 be "better" than the API exposed in Example 2 and vice versa? What are the justifications for supporting this decision?

After many years as a developer I still make that decision on the basis of feeling . I also noticed that over time the construction of the 2 example (which was rare, and readily refactored for 1 in my code) began to become more acceptable and even preferable in most situations. However, until today I have difficulty formalizing the reasons that lead me to choose one building or another.

    
asked by anonymous 05.03.2014 / 05:31

2 answers

5

In fact, neither option is ideal. I will briefly discuss each one of them and then propose an alternative.

Option 1: save state in A

This solution, although inelegant, may be feasible at least in cases where there is no parallelism (i.e. only an algorithm running on a single thread will have access to A ). In this case, using a variable representing " C current" greatly simplifies its use.

However, in the case of an API for third parties, it is difficult to predict how it will be used. Taking the example a question I recently answered, the fact that the library matplotlib using a" current image "and a" current subplot "to direct all your operations makes it complex to work with multiple images and subplots at the same time (even in the absence of parallelism).

Option 2: pass C as parameter always

The biggest advantage here is flexibility, the biggest disadvantage is the verbosity of the code (always having to keep repeating the passing of c as a parameter). Most of the time this is only an inconvenience, so this solution is valid without reservations. It is not ideal, but it is valid.

Option 3: "currying" of objects

The concept of currying , when supported by a programming language, usually applies to a single function. For example, given A.metodo1(C, D, E):F could be set C as curry(a.metodo1, c) -> fn(D, E):F . However, this is of little help to the client code, as it will need to combine two or more A methods to perform its function.

However, if we extrapolate this concept to the entire A class, we can create an auxiliary class X that "fixes" the instance of C [in addition to A itself] and exposes only the A that involve the C class. For example:

class X {
    private A a;
    private C c;

    public X(A a, C c) {
        this.a = a;
        this.c = c;
    }

    public metodo1() {
        // faz algo com a e c   
    }

    public metodo2() {
        // faz algo com a e c   
    }

    // Sem "metodo3"; somente os métodos em que A e C interagem
}

If convenient, A can serve as a factory for X :

class A {
    public X curry(C c) {
        return new X(this, c);
    }
}

In this way you simplify the interface (ie create a façade ) without having to "pollute" class A with the introduction of a property that does not correspond to the conceptual [static] relationship between the A and C entities.

    
05.03.2014 / 06:31
4

Some interesting references on the subject:

SOE-Parameter vs. Member variables

Top Points:

  • Class variables are considered object state
  • Using an instance variable implies maintaining state between two method calls. If the value stored in C does not have to live between two calls then the instance variable should not exist
  • The lower the lexical scope and lifetime of a variable, the less the possibility of misuse and the better for the elimination of resources.

SOE: Instance variables vs parameter passing? Is there an argument?

Main points:

  • On the positive side, use of instance variables prevents the proliferation of parameters in methods. The readability of methods with many arguments is impaired. The Clean Code book argues that methods should have no more than three parameters.
  • On the down side, using instance variables just to avoid passing them as a parameter is not a good idea and swells the class.

Programmers: Ruby - when to use instance variables vs parameters between methods?

Main points:

  • The decision between one style and another depends on the role of C before the entire class A . If the information carried in C is relevant to most of the class, then it makes sense to have an instance variable. Example: An object representing a bank account that needs the holder for almost all actions.
  • On the other hand, if the data is specific to a particular method (and auxiliary methods) they must "travel" as parameters or intermediate objects.
05.03.2014 / 06:15