0

Ich habe einen Elternteil TypenWählen Sie Implementierung basierend auf der Art des Objekts in Java

public class IObject{} 

und viele Unterklassen haben kann (sogar neue in der Zukunft)

public class Object1 extends IObject{} 
public class Object2 extends IObject{} 
public class Object3 extends IObject{} 
... 
public class ObjectN extends IObject{} 

Dann muss ich basierend auf der Art dieser Objekte verschiedene Operationen durchführen.

public class StrategyForObject1(){void do{}} 
public class StrategyForObject2(){void do{}} 
public class StrategyForObject3(){void do{}} 
... 
public class StrategyForObjectN(){void do{}} 

Deshalb mag ich aus meiner Kontextklasse:

public Conext { 
    IObject o; 

    public void setObject(IObject o) { 
     this.o = o; 
    } 

    void logic() { 
     if (o instanceOf Object1) { 
      new StrategyForObject1().do(); 
     } 
     if (o instanceOf Object2) { 
      new StrategyForObject2().do(); 
     } 
     if (o instanceOf Object3) { 
      new StrategyForObject3().do(); 
     } 
     ... 
     if (o instanceOf ObjectN) { 
      new StrategyForObjectN().do(); 
     } 
    } 
} 

So basierend auf der Art verschiedene Algorithmen auszuführen, aber ich will wie in Strategiemustern erweiterbar sein, wenn ich neue Unter hinzufügen muß Klasse von IObject nur um neue StrategyForObject**N** Klasse hinzuzufügen, aber nicht um die Conext Klasse zu ändern. Im Strategie-Muster müssen wir die Strategie angeben, aber hier müssen wir das Gegenteil tun: um die Strategie basierend auf der Art des Objekts zu wählen. Wie geht das in Java am besten?

bearbeiten: Die IObject kann nicht geändert werden, um zusätzliche Methoden hinzuzufügen. Ich muss Logik von Daten trennen, also ist es nicht wünschenswert, Implementierung der Logik in Object1 Klasse zum Beispiel hinzuzufügen.

+0

Dieser Beitrag für Sie nützlich sein können: http://stackoverflow.com/questions/255214/when-should-i-use-the-visitor-design-pattern/35406737 # 35406737 –

Antwort

2

Zunächst sollte Ihre IObject Klasse abstrakt sein, da sie nur durch andere Klassen erweitert werden soll. Dann können Sie eine Methode darin erklären, die von Klassen überschrieben werden müssen, die von ihm erben, wie folgt aus:

public abstract class IObject { 
    abstract void do(); 
} 

dann alle Klassen, die sie implementieren müssen diese Methode mit Ihrer benutzerdefinierten Logik außer Kraft setzen:

public class Object1 extends IObject { 
    @Override 
    void do() { 
    //custom logic 
    } 
} 

Mit anderen Worten, Sie sollten do() innerhalb Object1 statt StrategyForObject1 setzen.

Mit dieser Struktur können Sie do() für ein generisches Objekt vom Typ IObject aufrufen, da alle untergeordneten Elemente IObject die Methode do() implementieren. So in Ihrer Logik-Methode können Sie nur dies tun:

void logic(){ 
o.do(); 
} 
+0

Während dies funktioniert, hat es für einen einfachen Fall seine Nachteile. Zwei wichtige, die ich sehe. Zuerst müssen Sie Geschäftslogik in Ihr Objekt einbetten. Zweitens können Sie nur eine Art von Logik implementieren. Das Besuchermuster ermöglicht Ihnen einen modularen und erweiterbaren Ansatz. – Ulises

+0

@Ulises Ich stimme zu, dass je nach den Bedürfnissen des Autors entweder Ihre oder meine Lösung die beste sein könnte. Es gibt Zeiten und Orte für beide. Die Antwort des Besuchermusters erhielt meine Antwort – nhouser9

1

IObject könnte eine abstrakte Methode haben, do().

Dann ruft Context logic() Methode nur o.do().

Dies ist ein klassisches Beispiel für Polymorphie.

+1

Sie haben meine Antwort nur mit weniger Erklärung kopiert. – nhouser9

+0

@ nhouser9 nicht streiten. Ihr werdet beide abstimmen :) – Xelian

+0

Ich bin ein langsamer Typ auf meinem Handy, und manchmal ist kurz besser. @ nhouser9, Ihre Antwort würde durch eine Erwähnung von (und möglicherweise eine Verbindung zu) "Polymorphismus" verbessert werden. – user949300

1

Schauen Sie sich das Besuchermuster an. Ich denke, es ist genau das, wonach du suchst.

Edit: Um zu klären:

import java.util.Arrays; 
import java.util.List; 

public class Test { 
    public static abstract class IObject { 
     public abstract void doSomeWork(StrategyVisitor strat); 
    } 

    public static class Object1 extends IObject { 
     @Override 
     public void doSomeWork(StrategyVisitor strat) { 
      strat.doWork(this); 
     } 
    } 

    public static class Object2 extends IObject { 
     @Override 
     public void doSomeWork(StrategyVisitor strat) { 
      strat.doWork(this); 
     } 
    } 

    public static class Object3 extends IObject { 
     @Override 
     public void doSomeWork(StrategyVisitor strat) { 
      strat.doWork(this); 
     } 
    } 

    public static interface StrategyVisitor { 
     void doWork(Object1 o); 

     void doWork(Object2 o); 

     void doWork(Object3 o); 
    } 

    public static void main(String[] args) { 
     List<IObject> objs = Arrays.asList(new Object1(), new Object2(), new Object3()); 

     StrategyVisitor visitor = new StrategyVisitor() { 
      @Override 
      public void doWork(Object1 o) { 
       System.out.println("Object1"); 
      } 

      @Override 
      public void doWork(Object2 o) { 
       System.out.println("Object2"); 
      } 

      @Override 
      public void doWork(Object3 o) { 
       System.out.println("Object3"); 
      } 
     }; 

     objs.stream().forEach(o -> o.doSomeWork(visitor)); 
    } 
} 

(Siehe https://en.wikipedia.org/wiki/Visitor_pattern)

3

Ich glaube, Sie brauchen das Besuchermuster zu implementieren. Im Grunde genommen für das, was man hätte es so etwas wie folgt aussehen:

interface IObjectVisitor { 
    void visit(IObject1 obj1); 
    void visit(IObject2 obj2); 
    ... 
    void visit(IObjectN objN); 
}  
interface IObjectVisitable { 
    void accept(IObjectVisitor visitor); 
} 
public abstract class IObject implements IObjectVisitable { 
    ... 
} 
public class IObject1 extends IObject { 
    public void accept(IObjectVisitor visitor) { 
     visitor.visit(this); 
    } 
} 
public class IObject2 extends IObject { 
    public void accept(IObjectVisitor visitor) { 
     visitor.visit(this); 
    } 
} 
... 
public class IObjectN extends IObject { 
    public void accept(IObjectVisitor visitor) { 
     visitor.visit(this); 
    } 
} 
public class SomeLogicIObjectVisitor implements IObjectVisitor { 
    void visit(IObject1 obj1) { 
     //something with obj1 
    } 
    void visit(IObject2 obj2) { 
     //something with obj2 
    } 
    ... 
    void visit(IObjectN objN) { 
     //something with objN 
    } 
} 

Dann sind Sie haven einige Logik zu einem gewissen IObject wie folgt anzuwenden:

public void someLogic(IObject obj) { 
    SomeLogicIObjectVisitor visitor = new SomeLogicIObjectVisitor(): 
    visitor.visit(obj); 
} 

Object-Oriented weise, dies ist das beste Muster, das Sie kann implementieren. Der Grund dafür ist, dass es Ihnen einen modularen und erweiterbaren Ansatz ermöglicht, indem Sie die richtige Trennung von Bedenken anwenden. Sehen Sie sich zum Beispiel die Antwort von @ nhouser9 an. Während die Definition von abstract void do(); in IObject auf den ersten Blick zu funktionieren scheint, würden Sie Geschäftslogik in Ihr Domänenobjekt einbetten, das höchstwahrscheinlich nicht dorthin gehört. Wenn Sie nun eine andere Logik in Betracht ziehen, nennen wir sie "logic2". Sie haben jetzt keine andere Möglichkeit, als abstract void do2(); für jede IObject-Implementierung zu erstellen und Geschäftslogik dort einzubetten. Mit dem Besuchermuster ändern sich IObject-Implementierungen nicht und Sie betten keine Logik in die IObjects ein. Erstellen Sie einfach einen neuen Besucher, Logic2IObjectVisitor, und implementieren Sie dort die Logik jeder IObject-Implementierung. Und Sie es so nennen würde:

public void someLogic2(IObject obj) { 
    Logic2IObjectVisitor visitor = new Logic2IObjectVisitor(): 
    visitor.visit(obj); 
} 
+0

Eine Erklärung dafür, wann Sie ein Besuchermuster anstelle eines einfacheren Polymorphismus verwenden würden, würde dieser Antwort sehr helfen. – user949300