È sicuro restituire un nuovo oggetto dal metodo statico?

3

Va bene avere una classe come questa

public class Weapon {
    private string name;
    private int might;
    // etc...

    private Weapon(String name, int might) {
        this.name = name;
        this.might = might;
    }

    public static final Weapon Alondite = new Weapon("Alondite", 16);
    // 100++ weapon
}

Quindi chiamare l'arma in qualsiasi punto del progetto, come questo Weapon.Alondite , creerà un nuovo oggetto ogni volta che viene chiamato il membro statico metodo ?

O dovrei fare così, per garantire che l'oggetto venga creato una sola volta

public class Weapon {
    private string name;
    private int might;
    // etc...

    private Weapon(String name, int might) {
        this.name = name;
        this.might = might;
    }

    private static Weapon mAlondite;
    public static Weapon Alondite() {
        //if (mAlondite == null) {
        //    mAlondite = new Weapon("Alondite", 16);
        //    return mAlondite;
        //} else {
        //    return mAlondite;
        //}

        // EDIT: as suggested by everyone
        if (mAlondite == null) {
            mAlondite = new Weapon("Alondite", 16);
        }
        return mAlondite;
    }
}
    
posta SIRS 19.01.2018 - 03:37
fonte

3 risposte

9

No, il tuo primo snippet di codice non creerà una nuova arma ogni volta che ne fai riferimento.

Il secondo esempio che hai pubblicato è un esempio del modello singleton.

In base al tuo commento in fondo al tuo primo esempio, sembra indicare che avrai oltre 100 istanze di diverse armi. Questo è molto Hai ragione che non vuoi necessariamente avere più di una istanza della stessa arma (una potrebbe per motivi diversi, ma i tuoi esempi sembrano indicare singleton-ness).

Potresti considerare cosa potrebbe accadere se avessi bisogno di creare un altro tipo di arma, o forse un centinaio o un migliaio. Potresti non voler ricompilare ogni volta. Altrimenti, lo scopo della classe potrebbe essere interpretato erroneamente come una lista di tipi di armi, non l'arma stessa.

In base al tuo esempio, sembrerebbe che i 100 tipi di armi differiscano solo per nome e potenza. In questo caso, essendo solo diversi nei dati, non nel comportamento, potrei prendere in considerazione la possibilità di leggerli da un file o da qualcos'altro e di fornire un mezzo per cercarli (simile al pattern del repository).

public class WeaponLookup {

    private Map<String, Weapon> weapons = new HashMap<>();

    public WeaponLookup(Map<String, Weapon> weapons) { // loaded from file or something
        this.weapons = weapons;
    }

    public Weapon Lookup(String name) {
        return weapons.get(name);
    } 
}

Hai menzionato in un commento che le tue armi avranno molti attributi, non limitati a due. Penso che questo si muova maggiormente nel favore dell'uso di un file di dati esterno non compilato, anziché essere compilato nella classe.

Puoi confrontare qualcosa del genere

{
    "weapons" : [
        {
            "name" : "Almonite",
            "might" : 16,
            "def-bonus" : 7,
            "spd-bonus" : 9
        },
        {
            "name" : "Alphite",
            "might" : 22,
            "def-bonus" : 2,
            "spd-bonus" : 3
        },
        {
            "name" : "Betite",
            "might" : 16,
            "def-bonus" : 11,
            "spd-bonus" : 4
        },
        {
            "name" : "Gammite",
            "might" : 12,
            "def-bonus" : 7,
            "spd-bonus" : 7
        },
        {
            "name" : "Deltite",
            "might" : 19,
            "def-bonus" : 6,
            "spd-bonus" : 5
        },
        {
            "name" : "Thetite",
            "might" : 11,
            "def-bonus" : 2,
            "spd-bonus" : 11
        }
    ]
}

Per qualcosa di simile

public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);

Guardando questo esempio, puoi dire quale di quei numeri appartiene a quale campo; è l'11 di Betite spd-bonus o def-bonus? Non posso certamente dirlo. Potrei andare dal costruttore e vedere di cosa si tratta (è def-bonus), ma non voglio davvero farlo. Se ce ne saranno 100+, sarebbe su questo lungo

public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);
public static final Weapon Deltite = new Weapon("Deltite", 19, 6, 5);
public static final Weapon Thetite = new Weapon("Thetite", 11, 2, 11);
public static final Weapon Almonite = new Weapon("Almonite", 16, 7, 9);
public static final Weapon Alphite = new Weapon("Alphite", 22, 2, 3);
public static final Weapon Betite = new Weapon("Betite", 16, 11, 4);
public static final Weapon Gammite = new Weapon("Gammite", 12, 7, 7);

Vuoi rilasciare una nuova versione del tuo programma ogni volta che apporti una modifica che non influisce veramente sulla funzionalità? Io non. Preferirei avere una sorta di controllo degli aggiornamenti che scarica l'ultima versione del file di dati. La funzionalità non cambia mai, ma improvvisamente è possibile aggiungere altre migliaia di armi. O persino rimuovendo le armi; se aggiungi un'arma che finisce per essere più potente del previsto, puoi facilmente rimuovere la voce dal file; invece di ricostruire il tuo codice, testarlo e renderlo disponibile per i tuoi client da scaricare.

    
risposta data 19.01.2018 - 03:56
fonte
4
public static final Weapon Alondite = new Weapon("Alondite", 16);

Then calling the weapon anywhere in the project, like this Weapon.Alondite, will this create new object every time the static method called?

Bene, non lo farà. Questo non è un metodo. Questo è un attributo membro pubblico archiviato nella memoria statica. Arma sarà costruita solo una volta da questa cosa. L'unica cosa "non sicura" su questo è che è effettivamente globale.

Il tuo secondo elenco di codici è solo un tentativo del modello singleton . Che stabilisce anche un globale.

Seriamente, perché non devi creare Weapon una volta in main() e passare le copie del suo riferimento a qualsiasi cosa ne abbia bisogno?

    
risposta data 19.01.2018 - 03:51
fonte
1

Cercherò di rispondere da un'angolazione diversa. Sembra che tu stia cercando di creare determinate istanze di armi con attributi diversi (e potenzialmente di comportamento). Posso suggerirti di andare con il polimorfismo e invece avere qualcosa di simile a

public abstract class Weapon {
  private string name;
  private int might;
  // etc...
  public abstract void attack();
}
public class Alondite extends Weapon {
  public Alondite(){
    super("Alondite", 16);
  }
  @Override
  public void attack(){
    //Swoosh
  }
}
public class Kryptonite extends Weapon {
  public Kryptonite(){
    super("Kryptonite", 100);
  }
  @Override
  public void attack(){
    //Boom
  }
}

Ad ogni modo, per rispondere alla tua domanda, è perfettamente sicuro restituire un'istanza dal metodo statico a seconda del tuo intento. In base alla tua domanda e all'osservazione di tutti gli altri, sembra che tu voglia solo un'istanza di ciascuna arma e che tu stia guardando una sorta di schema di singleton. In tal caso, e estendendo la mia risposta sopra, cambia i costruttori in privato e crea un metodo getInstance statico simile al tuo secondo esempio. Vorresti qualcosa di simile:

public class Alondite extends Weapon {
  private static Alondite instance = new Alondite();
  public static Alondite getInstance(){return instance;}
  private Alondite(){
    super("Alondite", 16);
  }
  // etc...
}

Ciò assicurerebbe che un'istanza di ogni arma venga creata ovunque, in quanto possono ottenere solo un'istanza attraverso getInstance che, a sua volta, viene prelevata da un membro statico.

A proposito, c'è un pericolo di infilamento nel modo in cui hai scritto il tuo secondo campione. Se due thread sono entrambi nel blocco (alondite == null) , entrambi creerebbero istanze separate delle armi. Ciò significherebbe che i due thread punterebbero a due istanze diverse che chiaramente non sono ciò che intendiamo fare.

    
risposta data 19.01.2018 - 07:37
fonte

Leggi altre domande sui tag