2015-03-20 3 views
17

Was ist der beste Weg, um die Reihenfolge der Dinge auf der Grundlage einiger Bedingungen zu manipulieren (anders als schreiben sie wieder mit der anderen Reihenfolge)?Ändern der Reihenfolge der Methode Aufruf für verschiedene Instanzen einer Klasse

Sagen wir, es gibt eine Personenklasse und jedes Objekt der Person repräsentiert einen anderen Menschen.

class Person{ 
    int eatingPriority = 3; 
    int sleepingPriority = 2; 
    int recreationPriority = 1; 

    void eat() {/*eats*/} 
    void sleep() {/*sleeps*/} 
    void watchTv() {/*watches tv*/} 

    void satisfyNeeds() { 
     //HOW TO DO THIS 
    } 
} 

Wie kann ich die satisfyNeeds() Methoden, um die anderen drei Verfahren auf der Grundlage ihrer Priorität nennen?

Hinweis: Ich möchte klarstellen, dass sich Prioritäten von Person zu Person ändern können.

+2

Die einfachste ist eine abstrakte Klasse mit zwei Methoden zu erstellen: 'getPriority()' und 'run()'. Erstellen Sie dann für jede Aktivität einen Insurance. Schließlich können Sie Instanzen dieser Aktivitäten in eine Liste aufnehmen und nach Priorität sortieren. –

+2

@ArnaudDenoyelle oder verwenden Sie eine 'PriorityQueue' – SpaceTrucker

+0

Ich habe den Zweck des Programms gefragt. Wir versuchen, den saubersten Weg zu finden, den Ablauf des Programms zu manipulieren. In diesem Beispiel nehmen wir an, dass wir eine KI für ein Spiel erstellen, in dem Personen simuliert wurden. Wenn Sie beide hungrig und müde sind, würden Sie zuerst schlafen oder essen? Wenn Ihre Schlafpriorität höher ist, schlafen Sie zuerst, sonst essen Sie vor dem Schlafen. Es ist auch möglich, die Prioritäten im laufenden Betrieb zu ändern. Wir können den Schlaf- und Nahrungsbedarf messen und daraus eine Priorität machen. Beachten Sie, dass der Code in der Frage eine vereinfachte Version ist, um das Problem zu veranschaulichen – WVrock

Antwort

7

können Sie diesen Code

import java.util.Arrays; // must be imported 
int[] priorities = {sleepPriority, eatPriority, recreationPriority}; 
Arrays.sort(priorities); 
for (int i=priorities.length-1; 0<=i; i--) { 
    int priority = priorities[i]; 
    if (priority == sleepingPriority) { sleep(); } 
    if (priority == eatingPriority) { eat(); } 
    if (priority == recreationPriority) { watchTv(); } 
} 

es setzt Grundsätzlich verwenden, um die Prioritäten in einem Array, sortiert das Array und führt eine Schleife für sie auf, die Funktionen auszuführen.

+0

erfordert -1 zu dem Startwert i. Ursachen outOfBoundsException. 'int i = priorities.length -1' – WVrock

+0

Oh .. Ich werde es jetzt überprüfen. –

+0

OK, ich habe es behoben. Es sollte jetzt funktionieren. Ich fügte die-1 als @WVrock hinzu. –

4

Sie sollten eine Karte Eigenschaft in Person Klasse einführen, wo Methoden priorisieren, zum Beispiel:

class Person { 

... 
private Map<Integer, Method> methodsPriority = new HashMap<>(); 
... 
public Person setEatingPriority(int priority) { 

    methodsPriority.put(priority, /* put 'eat' method reference here*/); 
    return this; 
} 

public Person setSleepingPriority(int priority) { 

    methodsPriority.put(priority, /* put 'sleep' method reference here*/); 
    return this; 
} 

public Person setWatchingTVPriority(int priority) { 

    methodsPriority.put(priority, /* put 'watch TV' method reference here*/); 
    return this; 
} 

public void satisfyNeeds() { 

    Collection<Integer> keys = methodsPriority.keySet(); 
    Collections.sort(keys); 
    for(Integer key: keys) 
    methodsPriority.get(key).invoke(this); 
} 



... 
} 

Und es kann in der nächsten Weise verwendet werden:

Person Anna = new Person() 
.setEatingPriority(1) 
.setSleepingPriority(2) 
.setWatchingTVPriority(3); 

Person Bob = new Person() 
.setEatingPriority(3) 
.setSleepingPriority(2) 
.setWatchingTVPriority(1); 

Anna.satisfyNeeds(); 
Bob.satisfyNeeds(); 
13

Sie können dies tun, mit 1 Klasse und 1 Schnittstelle.

public class Person { 
    int eatingPriority = 3; 
    int sleepingPriority = 2; 
    int recreationPriority = 1; 

    PriorityQueue<Action> actions; 

    void eat() { } 

    void sleep() { } 

    void watchTv() { } 

    public Person() { 
     actions = new PriorityQueue<Action>(new Comparator<Action>() { 
      @Override 
      public int compare(Action o1, Action o2) { 
       return o2.getPriority() - o1.getPriority(); 
      } 
     }); 

     actions.add(new Action() { 
      @Override 
      public int getPriority() { 
       return eatingPriority; 
      } 
      @Override 
      public void execute() { 
       eat(); 
      } 
     }); 

     actions.add(new Action() { 
      @Override 
      public int getPriority() { 
       return sleepingPriority; 
      } 
      @Override 
      public void execute() { 
       sleep(); 
      } 
     }); 

     actions.add(new Action() { 
      @Override 
      public int getPriority() { 
       return recreationPriority; 
      } 
      @Override 
      public void execute() { 
       watchTv(); 
      } 
     }); 
    } 

    public void satisfyNeeds() { 
     for (Action action : actions) { 
      action.execute(); 
     } 
    } 

    interface Action { 
     public int getPriority(); 
     public void execute(); 
    } 
} 
+0

Sie können auch Ihre Klassenstruktur beibehalten und Ihre Methoden eat(), sleep() und watchTv() von geeigneten execute() -Methoden aufrufen. – Maksim

+1

Zu viele Boilerplate ... – Mik378

+2

Danke! Nette Idee, es ist sinnvoll hier PriorityQueue anstelle von ArrayList zu verwenden. – Maksim

10

Hier ist eine weitere mögliche Implementierung ist:

abstract class Need { 
    abstract void satisfy(); 
} 

class Eat extends Need { 
    @Override 
    public void satisfy() { /* eat ...*/} 
} 

class Sleep extends Need { 
    @Override 
    public void satisfy() { /* sleep ...*/} 
} 

class DrinkBeer extends Need { 
    @Override 
    public void satisfy() { /* drink beer ...*/} 
} 

class Person{ 
    // TreeMap will sort the map in the key's natural order (a int here) 
    private Map<Integer, Need> needs = new TreeMap<>();  

Person() { 
    add(new Eat(), 3); 
    add(new Sleep(), 2); 
    add(new DrinkBeer(), 1); 
} 

void add(Need need, int priority) { 
    needs.put(Integer.valueOf(priority), need); 
} 

void satisfyNeeds() { 
    for(Need need : needs.values()) 
     need.satisfy(); 
    } 
} 
+0

'needs.put (Integer.valueOf (priority), need)' kann einfach als 'needs.put (priority, need)' geschrieben werden. – VGR

5

die richtige Reihenfolge der drei Elemente zu finden, kann einfach so geschehen:

void satisfyNeeds() { 
    boolean eatFirst = eatingPriority>Math.max(sleepingPriority,recreationPriority); 
    if(eatFirst) eat(); 
    if(sleepingPriority>recreationPriority) { 
     sleep(); 
     watchTv(); 
    } 
    else { 
     watchTv(); 
     sleep(); 
    } 
    if(!eatFirst) eat(); 
    } 

Natürlich wird es nicht skaliert, wenn Sie erhöhen die Anzahl der Aktionen. Für eine höhere Nummer können Sie sich eine der anderen Antworten ansehen.

9

Diese Lösung würde erfordern Java 8:

class Person { 

    void eat() {}; 
    void sleep() {}; 
    void watchTv() {}; 

    // Being in a List you can easily reorder the needs when you want to 
    List<Runnable> needs = Arrays.asList(this::eat, this::sleep); 

    // Alternatively, you can use a Map<Runnable, Integer> where the value is your 
    // priority and sort it (see http://stackoverflow.com/q/109383/1296402) 

    void satisfyNeeds() { 
     needs.forEach(r -> r.run()); 
    } 
} 
+0

Können Sie es ausarbeiten? Soll ich 'needs = Arrays.asList (() -> essen(),() -> sleep());' mit der gewünschten Reihenfolge schreiben, wann immer ich sie neu anordnen möchte? – WVrock

+0

@WVrock Sie können die Reihenfolge zunächst definieren und später neu anordnen, wenn sie sich ändert. Oder verwenden Sie eine 'Map', wenn Sie statische Prioritätswerte als Ganzzahlen haben (siehe Link). Vielleicht haben Sie "Presets", wie "final List needsDuringDayTime = ....; final Liste needsDuringNightTime = ... 'und dann setzen Sie sie in' satisfyNeeds() ':' Liste needs = isDayTime()? needsDuringDayTime: needsDuringNightTime'. – steffen

+0

@WVrock Oder stellen Sie sich vor, Sie haben Zähler oder Zeitstempel für die letzten Mahlzeiten, Schlafzeiten oder TV-Sitzungen und so ändern sich die Bedürfnisse dynamisch. Sie würden die 'List' mit einem benutzerdefinierten' Comparator' sortieren, wie 'Collections.sort (needs, customComparator);' – steffen