Zamodelować 2 warianty zależne od siebie

0

Nie znam wzorca projektowego, który by tu pasował.

Mamy 2 warianty i każdy z nich zawiera jakieś reguły + warianty są od siebie zależne tzn. wariant 1 A może nie pasować do wariantu 2 B. Jak to zamodelować?
Roboczo mam tak o:

enum Variant1 {

  A(A, B, C),
  B(B, Z),
  C(A)

  List<Variant2> variants2;

  List<Variant2> getAvaidableVariants2ForVariant1(Variant1 variant1) {
    return variant1.getVariants2();
  }

...

}
enum Variant2 {

  A("aaa", "aaaxxx"),
  B("bbb", "bbbyyy"),
  C("x"),
  Z("aaa")

  List<String> categories;

  List<String> getVaidableCategoriesForVariant2(Variant2 variant2) {
    return variant2.getCategories();
  }

...

}

jakaś inna struktura na to? A może w ogóle nie powinienem tego tak trzymać w runtimie tylko w bazie i za każdym razem odpytywać + cache.

5

Jak patrzę na ten kod to nie rozumiem co chcesz osiągnąć :P. Może podaj jakiś przykład bardziej z życia wzięty ;)
Co chcesz zamodelować?

0

ja tez nie rozumiem co autor chciał osiągnąć. Taki kod zastałem i każą mi to zrobić mądrzej. A HRka mi powiezdiała, że pracuję "z najlepszymi", więc wstyd nie zrobić i wstyd pytać WTF.

Podejrzewam, że chodzi o możliwość walidowania Variant1 do Variantu2 do category
np.

boolean validate(Variant1 var1, Variant2 var2, String category) {
  return var1.getAvaidableVariants2ForVariant1().stream().filter(v -> v.equals(var2)).anyMatch()
    && var2,getVaidableCategoriesForVariant2().stream().filter(categ -> categ.equals(category)).anyMatch();
}
0

jeszcze jest jedna metoda getAvaidableVariants1ForVariant2 kluczowa.

enum Variant1 {

  A(A, B, C),
  B(B, Z),
  C(A)

  List<Variant2> variants2;

  List<Variant2> getAvaidableVariants2ForVariant1(Variant1 variant1) {
    return variant1.getVariants2();
  }

  List<Variant1> getAvaidableVariants1ForVariant2(Variant2 variant2) {
    return Variant1.values().stream().filter(var1 -> var1.getVariants2().contains(variant2)).collect(Collectors.toList());
  }

...

}
enum Variant2 {

  A("aaa", "aaaxxx"),
  B("bbb", "bbbyyy"),
  C("x"),
  Z("aaa")

  List<String> categories;

  List<String> getVaidableCategoriesForVariant2(Variant2 variant2) {
    return variant2.getCategories();
  }

...

}
0

To jest jakiś kompletny bałagan. Zapytaj się autora, co miał na myśli - nie-pytanie to postawa juniorska. Poza tym często „mądrzej” znaczy „czytelniej”, „prościej”. Ja bym to zaorał i przepisał ;)

1
boolean validate(Variant1 var1, Variant2 var2, String category) {
  return var1.getAvaidableVariants2ForVariant1().stream().filter(v -> v.equals(var2)).anyMatch()
    && var2,getVaidableCategoriesForVariant2().stream().filter(categ -> categ.equals(category)).anyMatch();
}

To jest takie klasyczne niby programuje obiektowo ale nie wiem co to znaczy. Czemu nie masz jakichś metod w tych obiektach, np.: var1.matches(var2) && var2.hasCategory(category)? od razu lepiej wyglada, nie?

3

Gdzieś z tyłu głowy rozumiem, co tu się dzieje, bo to trochę, jak jakiś system sprzedażowy (ubezpieczenia, produkty finansowe) wygląda. W dodatku w jakiejś uproszczonej formie, bo masz tylko operator AND.
W ogólności masz tutaj do zamodelowania n-wymiarową tabelę, w której wypełnienie komórki uzależnione jest od jej współrzędnych.

  • Każdy wariant to jedna oś.
  • Każda wartość dla wariantu to wartość na danej osi.
  • Każda oś może zawierać elementy tylko na przecięciu z niektórymi osiami.

IMO, zamiast enumów zdefiniuj jedną klasę, która reprezentuje wariant:

class Variant{
	private final String name;

	private final Set<Variant> validSubVariants;

	public Variant(String name) {
		this.name = name;
		this.validSubVariants = new HashSet<>();
	}

	public Variant addSubVariant(Variant subVariant){
		validSubVariants.add(subVariant);
		return this;
	}

	public boolean containsSubVariant(Variant variant){
		return validSubVariants.contains(variant);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		Variant variant = (Variant) o;
		return name.equals(variant.name);
	}

	@Override
	public int hashCode() {
		return Objects.hash(name);
	}
}

i niech ona sobie już ogarnia, co jej jest potrzebne. I wtedy dla twojego Variant2 masz na przykład:

//A("aaa", "aaaxxx"),
Variant aaa = new Variant("aaa");
Variant aaaxxx = new Variant("aaaxxx");
Variant A2 = new Variant("A2").addSubVariant(aaa).addSubVariant(aaaxxx);
//B("bbb", "bbbyyy"),
Variant bbb = new Variant("bbb");
Variant bbbyyy = new Variant("bbbyyy");
Variant B2 = new Variant("B2").addSubVariant(bbb).addSubVariant(bbbyyy);
//C("x"),
Variant x = new Variant("x");
Variant C2 = new Variant("C2").addSubVariant(x);
//Z("aaa")
Variant Z2 = new Variant("Z2").addSubVariant(aaa);

Jest to o tyle wygodne, że można zaczytać całą tablicę wariantów z pliku (mam dziwne wrażenie, że to jest jakaś wariacja jednego zadania z AoC 2020). Podobnie modelujesz Variant1 mając już zdefiniowane warianty drugiego i trzeciego poziomu.

I nie ma na to wzorca.

0

Jakbyś to wytłumaczył na konkretnych produktach byłoby o wiele łatwiej to załapać, niż Twoją abstrakcję. Jeśli sam te założenia rozumiesz a nie możesz opisywać prawdziwego produktu na którym pracujesz to wymyśl jakieś realne odniesienie - porównaj to do jakichkolwiek innych wymyślonych produktów.

0

OK, odnowię pytanie i skonkretyzuje, bo już trochę porozkminiałem.

Jak jest lepiej zrobić?

tak:


enum Variant1 {

  A (List.of(Variant2.A, Variant2.B),
  B (List.of(Variant2.A);

  private List<Variant2> variants2;

  Variant1(List<Variant2> variants2) {
    this.variants2 = variants2;
  }

  Variant2 getAvailableVariant2() {
    return variants2;
  }
}

czy tak:


enum Variant1 {
  A, B;
}

class VariantRules {

  private EnumMap<Variant1, Variant2> var1Var2Rules;

  VariantRules() {
    this.var1VarRules = createVar1Var2Rules();
  }

  Variant2 getAvailableVariant2(Variant1 variant1) {
    return var1Var2Rules.get(variant1);
  }

  private void createVar1Var2Rules() {
    var1Var2Rules.put(Variant1.A, List.of(Variant2.A, Variant2.B));
    var1Var2Rues.put(Variant1.B, List.of(Variant2.B));
  }
} 
0

@straznik-tagu: Napisz sobie kawałek kodu, w którym korzystasz z podejścia1 i podejścia2, zobacz, które jest wygodniejsze dla Ciebie, działa i generuje czytelniejszy kod.

Dla mnie obydwa wyglądają makabrycznie. Możliwe, że to przez brak szerszego kontektstu w jakim problem jest rozwiązywany. Pierwsze skojarzenie, które mam to "wariant, ale k**a, czego wariant?"
Rozumiem, że mogą być Produkty, Usług, które (nie) są ze sobą zgodne (np. dostajesz od marketingu reguły, macierz zgodności produktX zgodny z produktemY, która opisuje, ze możesz upgradować swoją usługę np. Konto Student do Konto Firma, ale Konto Firma do Student, to już nie) i możesz chcieć to jakoś jakoś zamodelować, np. tak jak napisał Ci @Koziołek

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