Qual è il modo OO giusto per creare una classe contatore / inventario che funzioni per i conteggi differenziati e indifferenziati?

2

Stai scrivendo un videogioco sul commercio di fagioli. Fagioli rossi, fagioli neri, fagioli borlotti, lo chiami. Come tutti sanno, tutti i fagioli sono uguali. Scrivi la classe "Inventario" per un commerciante in quel videogioco come segue (saltando tutti i controlli null):

    class BeansInventory{
HashMap<BeanType,Integer> amountsOwned;

public void receive(BeanType typeReceived, int amount)
{amountsOwned.put(typeReceived,amountsOwned.get(typeReceived)+amount)}

public void remove(BeanType typeRemoved, int amount)
{amountsOwned.put(typeRemoved,amountsOwned.get(typeRemoved)-amount)}

public Integer amountOwned(BeanType type)
{amountsOwned.get(type)}
}

Funziona bene per anni. Poi improvvisamente qualcun altro ha la grande idea di aggiungere al gioco il caffè in grani. Come tutti sanno, ogni singolo chicco di caffè è completamente diverso dall'altro. Quindi non puoi semplicemente aggiungere caffè come un altro tipo di fagiolo. Ogni chicco di caffè è la sua istanza. La classe di inventario del caffè è simile a questa:

class CoffeeInventory{
    HashMap<CoffeType,List<CoffeeBeans>> coffeOwned;

    public void receive(CoffeType typeReceived, CoffeeBeans... beans)
    {coffeOwned.get(typeReceived).addAll(beans)}

    public void remove(CoffeType typeRemoved, CoffeeBeans... beans)
    {coffeOwned.get(typeRemoved).removeAll(beans)}

    public Integer amountOwned(CoffeType type)
    {amountsOwned.get(type).size()}
    }

Ma ora hai un sacco di problemi. Hai due API per la stessa attività. Tutta l'infrastruttura di trading ora deve controllare attentamente se si tratta di fagioli pinto o chicchi di caffè e chiama un inventario diverso e un metodo diverso con una firma diversa per quello che è dopo lo stesso compito: "memorizza questo".

Quindi ora ho questo codice che viene riempito di if assegni e instanceof e tutti gli altri segni di odore di codice. Ma non riesco a capire un modo per utilizzare un'unica semplice API. Non ho idea di cosa sia la cosa giusta da fare.

    
posta CarrKnight 11.05.2014 - 01:32
fonte

1 risposta

1

La tua BeansInventory è diversa dalla tua CoffeeInventory . In realtà non lo chiamerei nemmeno "inventario" perché non memorizza le cose ma piuttosto traccia gli importi. Fruthermore, la tua classe CoffeeInventory non mostra alcun metodo per restituire gli oggetti bean memorizzati ma presumo che questo sia richiesto da qualche parte, quindi non possiamo usare contatori semplici come in BeansInventory .

Quindi per evitare i tuoi controlli per distinguere tra chicchi di caffè e altri fagioli, la soluzione pulita sarebbe di non fare alcuna differenza tra i fagioli!

class BeansInventory{
  HashMap<BeanType,Integer> amountsOwned;

  public void receive(BeanType typeReceived, int amount) {
       amountsOwned.put(typeReceived,amountsOwned.get(typeReceived)+amount)
  }

  public void receive(BeanType typeReceived, Beans beans) { //beans is a list of beans
       this.receive(typeReceived, beans.size())
  }

  //...
}

In questo modo non importa in quale inventario vengono inseriti i bean e in cima non devi modificare l'API esistente. Solo la gestione tra gli inventari è diversa, ma si comportano allo stesso modo. Ovviamente questo significa che entrambi dovrebbero implementare un Inventory Interface con metodi generici come receive(Bean bean) , remove(Bean bean) , contains(Bean bean) e così via.

Dovresti anche considerare di renderlo più generico e iniziare a usare gli oggetti bean anche per i bean normali. Anche se sono forse tutti uguali. In questo modo non devi creare un inventario speciale per i fagioli che sembrano tutti uguali. (potrebbe darti comunque dei vantaggi in termini di prestazioni)

    
risposta data 11.05.2014 - 02:12
fonte