giovedì 14 luglio 2011

Aboliamo static

Su twitter ho proposto scherzosamente di abolire la parola chiave static dei linguaggi garbage collected. All'inizio era appunto uno scherzo, poi mi sono detto:

posso effettivamente fare a meno di static?
Innanzitutto, perché fare a meno di static? Perché può dare un sacco di problemi.

Factory

Prendiamo una classe e un'innocente metodo static per costruirla:


public class DumbClass {

  private String foo;
  public String getFoo() { return foo; }
  public void setFoo(String foo) { this.foo = foo; }

  private String initializedStuff;
  public String getInitializedStuff() { return initializedStuff; }

  private DumbClass(String foo, String initializedStuff) {
    this.initializedStuff = initializedStuff;
    this.foo = foo;
  }

  public static DumbClass create(Context c) {
    return new DumbClass( c.doSomethingToGetFoo(), c.doSomethingToGetStuff() );
  }
}

Inevitabilmente, come dice Alan Shalloway, le specifiche cambiano e uno dei vostri clienti vuole che, solo per lui, foo sia in CamelCase piuttosto che tutto MAIUSCOLO. E voi:
Facile: mettiamo in una libreria (che diamo solo a lui) una classe che estend.. Ops: non si può estendere, è un metodo statico! E se invece avessi fatto un'abstract factory?

public class DumbClass {

  private String foo;
  public String getFoo() { return foo; }
  public void setFoo(String foo) { this.foo = foo; }

  private String initializedStuff;
  public String getInitializedStuff() { return initializedStuff; }

  DumbClass(String foo, String initializedStuff) {
    this.initializedStuff = initializedStuff;
    this.foo = foo;
  }
}

public interface IDumbClassFactory {
  DumbClass create(Context c);
}

public class DefaultDumbClassFactory {
  public DumbClass create(Context c) {
    return new DumbClass( c.doSomethingToGetFoo(), c.doSomethingToGetStuff() );
  }
}

Allora basterebbe wrappare DefaultDumbClassFactory o fare un'altra implementazione di IDumbClassFactory e avrei fatto!
Morale: non usare metodi statici, meno che mai pubblici!

Campi privati

A volte capita di voler tenersi un contatore di istanze di una certa classe per sapere quante ce ne sono in giro. E si fa con un bel campo static:


public class Foo {

  private static int howMany;

  public Foo(Something s) {
    howMany++;
  }
  ...
}

Risultato? Scoprite che in realtà quel contatore non lo legge mai nessuno, anzi, se usate la libreria su un web server che gira per 2 anni di fila, alla fine vi va in overflow e causa un eccezione che ovviamente non gestite perché non ci avevate pensato. Oppure vorrete che non tenga traccia delle classi figlie, oppure per qualcuna sì e qualcuna no, e allora? Scoprite che vi serviva un'abstract factory.
Morale: quando sto per scrivere static ci penso due volte e quasi sempre alla fine scrivo: interface

Wolfsburg VW-Werk

1 commento:

Enrico ha detto...

...eppure credo che metodi di utilità sia corretto definirli statici, la clausola static infatti ne definisce l'indipendenza con qualsiasi istanza e questo è corretto dal momento che sono di utilità a qualsiasi istanza.