Sprawdzanie jakiego typu jest klucz w Mapie

0

Hej,

Jak napisac warunek sprawdzajacy typ klucza w Mapie? Jako parametr konstrukatora, mapa bedzie przyjmowac raz Map<Snack,Integer>, a raz Map<Drink,Integer>? Chacialbym, aby w zaleznosc co jest kluczem mapy, przypisywac te mape do konkretnego typu zmiennej.

public Order(Movie movie, Map map) {

    this.id = ++idCount;
    this.movie = movie;
    if(map.keySet() instanceof Snack){
        this.snackMap=map;
        this.priceOrder = movie.getPrize() + getSnacksPrice(snackMap);


    } else {
        this.drinkMap = map;
        this.priceOrder = movie.getPrize() + getDrinksPrice(drinkMap);

    }

    roundPriceOrder();
}
2

Że co, cała mapa innego typu?
Czy do jednej mapy wrzucasz Snack i Drink?
W pierwszym przypadku zrób generyka, zaś w drugim dopiero w pętli sprawdzaj.

3

@Grantuser:

Zostawmy na chwilkę ten Map<> na boku.

jeśli bardzo, ale to bardzo ci się wydaje, że musisz sprawdzać typy, to w 90% oznacza, że powinny dziedziczyć ze wspólnego przodka, i że ten przodek ma wystawiać metodę - ale nie informacyjną *), a akcyjną, czyli w konwencji

class SomethingToEat {
   void prepareToBeEaten()
}

Która dla klasy Jabłko by była "przekrój i wytnij koszyczek" a dla ziemniaka "obierz, ugotuj w posolonej wodzie"

*) informacyjną bym okreslił { return "Jabłko" } i { return "Ziemniak" }

2

W klasie mam miedzy innymi pola Map<Snack,Integer> snackMap oraz Map<Drink,Integer> drinkMap i w zaleznosc jaka mapa zostanie przekazana do konstruktora to zostanie ona przypisane do jego pola a drugie ma zostac nul

To się robi dwa konstruktory (albo nawet trzy)

1

@Grantuser:

Czytam, czytam, czytam, jestem praktycznie pewien, ze wpieprzyłes się w jakiś XY Problem.
Jaki prawdziwy problem ma to wszystko załatwić? Dac sumę ilości sztuk ? Powiedzolną na części? Coś innego ?

0

Zgaduję, że domena to kino. Zamawiający może chcieć tylko bilet na film albo bilet z jakimiś przekąskami typu popcorn, cola itp, więc klasa Order powinna mieć 2 konstruktory, ale lepiej, żeby były prywatne i wystawić metody fabrykujące createForMovieOnly(Movie movie) i createForMovieWithSnack(Movie movie, List<Snack> snacks). Czyli potrzebujesz po prostu jakieś klasy Snack, na podstawie, której będzie można dodawać różne przekąski no i potem w tych metodach wyliczasz cenę całego zamówienia czy to z samym biletem na film czy z żarełkiem.

1

jeśli już planujemy te mapy przekazywać w różne miejsca to moim zdaniem pasuje te mapy opakować (np. w record) oraz zabezpieczyć na wypadek dodania kolejnych wariantów (poprzez sealed - chociaż exhaustivity checks chyba jeszcze nie zostały zaimplementowane w javie w wersji stabilnej)

sealed interface Extras

record Drinks(map: Map<Drink, Integer>) implements Extras
record Snacks(map: Map<Snack, Integer>) implements Extras

p.s. nie wiem czy się to skompiluje, bo mało w javcę koduję (jestem scalowcem), ale obstawiam, że tak :)

3

i Snack i Drink mogą implementować jeden interefejs z metodą getPrise lub abstrakcyjną klasę z abstract polem prise

1

@Grantuser: masz skopany projekt, ale da się to naprawić bez głębokiego grzebania. Jest coś takiego jak wzorzec builder i może warto go przytulić:

public class Order{

    private Map snackMap;
    private Map drinkMap;
    private Movie movie;
    
    private Order( Movie movie){
     //...
    }

    public static class Builder{
         
      private Map snackMap;
      private Map drinkMap;
      private Movie movie;

      public Builder withMovie(Movie movie){this.movie = movie; return this;}
      public Builder withSnackMap(Map snackMap){this.snackMap = snackMap; return this;}
      public Builder withDrinkMap(Map drinkMap){this.drinkMap = drinkMap; return this;}

      public Order build(){
         if(this.snackMap !=null && this.drinkkMap !=null){
           throw new IllegalStateException("Jesz albo pijesz nie oba"); // zakładam, że mamy tylko jedną mapę różną od null
         }
         var order = new Order(movie);
         order.snackMap = snackMap;
         order.drinkMap = drinkMap;
         return order;      
      }
    }

}

i później w kodzie używasz tego:

new Order.Builder()
  .withMovie(movie)
  .withSnackMap(map)
  .build()

chyba lepsze rozwiązanie niż kombinowanie ze sprawdzaniem typu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1