java, wzorzec, porada co użyć i jak

0

Mam pewna klase, dajmy na to (pseudokod):

String type = getType();

if ("ALA".equals(type) {
  new ALAMode(x).execute(y);
} else if ("BEATA".equals(type) {
 new BEATAMode(x).execute(y):
}
...

Jaki jest prosty sposob na zrobienie tego "inteligentniej"?

Myślałem o czyms w stylu:
Class c = Class.forName("com.package." + type + "Mode");
Object obj = c.newInstance();

i pozniej przerzutowac jakos i zawolac execute, ale moze sa lepsze sposoby?

3

Class.forName to rak.
Alternatywa to taki np. rejestr:

final HashMap<String, BiFunction2<X,Y, ???> > reg   = 
reg.put("ALA", x,y -> new ALAMode(x).execute(y));
reg.put("BETA", x,y -> new BETAMode(x).execute(y));
...
...

[...]
reg.get(getType()).apply(x,y);

Albo lepiej jak ALAMode i BETAMode mają interfejs executable.
i wtedy

final HashMap<String, Function1<X, Executable> > reg   = 
reg.get(getType()).apply(x).execute(y);

i gotowe.

0

Dzieki!

Wyglada pro, musze doczytac troche :)

Tylko oprocz metody execute, chce moc wywolywac tez inne z tych klas (ze wspolnego interfejsu), potrzebuje wlasnie caly ten obiekt, zastanawiam sie w ogole nad czyms prostszym:

final HashMap<> reg = new HashMap<String, IMode>();
      reg.put("ALA", new ALAMode());
      req.put("BEATA", new BEATAMode());

      IMode mode = reg.get(getType());
      mode.setProps(x);

      mode.execute();
      mode.doSTh();
0
  1. A czy x jest znany przed budowaniem tego rejestru? Bo jeśli tak, to bym go przekazywał do konstruktorów tych AL i BEAT zamiast ustawiać setProps().
    A nawet jeśli nie, to wolałbym
mode.execute(x);

zamiast

mode.setProps(x);
mode.execute();
  1. A co robi getType()?
1
jarekr000000 napisał(a):

Class.forName to rak.
Alternatywa to taki np. rejestr:

final HashMap<String, BiFunction2<X,Y, ???> > reg   = 
reg.put("ALA", x,y -> new ALAMode(x).execute(y));
reg.put("BETA", x,y -> new BETAMode(x).execute(y));
...
...

[...]
reg.get(getType()).apply(x,y);

Albo lepiej jak ALAMode i BETAMode mają interfejs executable.
i wtedy

final HashMap<String, Function1<X, Executable> > reg   = 
reg.get(getType()).apply(x).execute(y);

i gotowe.

Jeszcze można zamiast .get wykorzystać .getOrDefault gdzie default to będzie nic nie robiąca lambda lub NullObject pattern. Wówczas zabezpieczamy się przed NPE.

1

A może coś w ten deseń:

enum Modes {
    ALA(new ALAMode()),
    BEATA(new BEATAMode());
    private final Mode mode;
    Modes(Mode mode){
        this.mode = mode;
    }
    
    Mode getModeObject(){
        return this.mode;
    }
}

interface Mode {
    void execute(int y);
}

class ALAMode implements Mode {
    @Override
    public void execute(int y) {
         System.out.println("ALA "+y);
    }
}
class BEATAMode implements Mode {
    @Override
    public void execute(int y) {
        System.out.println("BEATA "+y);
    }
}

Modes m = Modes.valueOf(getType());
m.getModeObject().execute(10);
0

ten enum tez wyglada fajnie, nie pomyslalbym o tym :)

Zastanawiam się nad bezpieczeństwem takiego rozwiazania ( w porównaniu do chamskiego new Mode w ifach).

Załózmy ze te Mody wolaja inne serwisy, a kolei wiele rzeczy będzie rownoczesnie wolac te Mody.

Ale rozumiem, że dopoki każdy Mode nie przechowuje stanu w obiekcie, tylko ma metodki, to metody daja nam bezpieczenstwo, że każde wywolanie jest niezalezne itp.

0

Jeśli obiekty implementujące Mode będą niemutowalne to nie powinno być problemów ze współbieżnością. Problemem jest tylko ewentualny argument konstruktorów klas implementujących Mode np. new ALAMode(x). Jeśli wartość x jest ściśle określona dla każdego moda to nie ma problemu tworzysz enum {ALA(new AlaMode(value_for_ALA)) ...}, ale jeśli nie to trzeba zrobić setera i kombinować np. aby x było typu AtomicXXX z pakietu java.util.concurrent.atomic, ale to już zależy jak wykorzystywany jest ten x.

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