Files
java-design-patterns/localization/de/active-object/README.md
T
Stefan SiebersandGitHub cd4753a660 docs: Improve existing German READMEs and add new ones (#3444)
* docs: reformulate text, add links to further languages and paragraph about the book in central README.md
(#2275)

* docs: shorten text for link to payhip
(#2275)

* docs: reformulate german translation for Abstract Document
(#2275)

* Create folder for Abstract Factory

* Create README.md for Abstract Document

* Translate README.md for Abstract Document to German

* correct typo

* docs: add class diagrams for all patterns
(#2275)

* docs: add missing words in abstract-factory.README.md
(#2275)

* docs: Create German README.md for Active Object

#2275
first text part

* docs: finish German translation of README.md for Active Object

* docs: translate actor-model into German

#2295

* docs: add German translation for Acyclic Visitor

#2295

* correct typo

* docs: Translate Singleton into German

#2295

* docs: Translate Prototype into German

#2295

* Delete localization/de/Abstract Factory

* insert line break

* correct typos in actor-model

* realignment of java code block

* docs: translate Adapter Pattern into German

#2295

* Update README.md

change 'lizenz' to 'Lizenz' in badge

* Update README.md

translate 'benefits' and 'trade-offs'

* remove additional bullet point after line break

* correct indentation

* docs: translate Dependency Injection into German

#2295

* docs: translate Bridge into German

#2295

* correct typos

* docs: Translate Builder into German

* delete english text

* little changes in formulation

* Update README.md

change link to image

* docs: remove spanish files
(#2275)

* docs: remove non-translated patterns
(#2275)

* Create README.md

docs: Translate Step Builder into German
#2275

* Create README.md

docs: Translate Fluent Interface into German
#2275

* eager is eifrig, not gierig

* Translate Chain of Responsibility into German

#2275
2026-06-03 20:20:05 +03:00

9.1 KiB

shortTitle, category, language, tag
shortTitle category language tag
Active Object Concurrency de
Asynchronous
Decoupling
Messaging
Synchronization
Thread management

Zweck

Active Object bietet eine zuverlässige Methode zur Behandlung asynchroner Prozesse, mit der reaktionsfähige Anwendungen und effizientes Thread-Management gesichert werden. Dies wird dadurch erreicht, dass die einzelnen Aufgaben in Objekte gekapselt werden, die in eigenen Threads (Steuerungsflüssen) mit eigener Nachrichtenwarteschlange aktiv sind. Durch diese Trennung bleibt der Hauptthread reaktionsfähig und Probleme wie direkte Threadmanipulation oder gemeinsamer Zugriff auf Zustände werden vermieden.

Detaillierte Erklärung

Reales Beispiel

Stellen Sie sich ein gut besuchtes Restaurant vor, in dem die Gäste Bestellungen bei den Kellner aufgeben. Die Kellner gehen nicht selbst in die Küche, um die Essen selbst zuzubereiten, sondern sie schreiben die Bestellungen auf Zettel und geben diese dem Küchenmanager. Der Manager organisiert eine Gruppe von Köchen, die die verschiedenen Mahlzeiten parallel zubereiten. Wenn ein Koch frei ist, nimmt er eine Bestellung aus der Warteschlange, bereitet das Essen zu und benachrichtigt den Kellner, sobald es fertig zum Servieren ist.

In dieser Analogie stehen die Kellner für die Client-Threads, der Küchenmanager für den Thread-Scheduler, und die Köche für die Methodenausführung in verschiedenen Threads. Die Organisation ermöglicht es, dass die Kellner immer weiter Bestellungen annehmen können, ohne durch die Essenszubereitung aufgehalten zu werden; so wie das Active-Object-Pattern den Methodenaufruf von der Ausführung trennt, um die Effizienz zu verbessern.

In einfachen Worten

Das Active-Object-Pattern trennt Methodenausführung und Methodenaufruf, um Parallelitätsgrad und Reaktionsfähigkeit in Multithread-Anwendungen zu verbessern.

Wikipedia sagt

Das Design-Pattern Active Object entkoppelt die Methodenausführung vom Methodenaufruf für Objekte, die in ihrem jeweils eigenen Thread arbeiten. Ziel ist, Parallelität dadurch zu ermöglichen, dass Methoden asynchron aufgerufen werden und ein Scheduler die Anfragen organisiert.

Das Pattern besteht aus sechs Elementen.

  • Ein Proxy stellt für Clients ein Interface mit öffentlich zugänglichen Methoden zur Verfügung.
  • Ein weiteres Interface definiert die Anfragen an ein aktives Objekt.
  • Eine Liste offener Client-Anfragen.
  • Ein Scheduler entscheidet, welche Anfrage als nächstes ausgeführt wird.
  • Die Implementation der Methoden.
  • Eine Callback-Variable zur Rückmeldung des Ergebnisses.

Ablaufdiagramm

Active Object sequence diagram

Programmbeispiel in Java

Die Orcs sind wilde und nicht zu bändigende Kreaturen. Anscheinend haben sie ihre eigene Steuerung, die nur von ihrem vorherigen Verhalten bestimmt wird. Um eine derartige Kreatur zu implementieren, können wir das Active-Objekt-Pattern benutzen.

public abstract class ActiveCreature {
    private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());

    private BlockingQueue<Runnable> requests;

    private String name;

    private Thread thread;

    public ActiveCreature(String name) {
        this.name = name;
        this.requests = new LinkedBlockingQueue<Runnable>();
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        requests.take().run();
                    } catch (InterruptedException e) {
                        logger.error(e.getMessage());
                    }
                }
            }
        }
        );
        thread.start();
    }

    public void eat() throws InterruptedException {
        requests.put(new Runnable() {
                         @Override
                         public void run() {
                             logger.info("{} is eating!", name());
                             logger.info("{} has finished eating!", name());
                         }
                     }
        );
    }

    public void roam() throws InterruptedException {
        requests.put(new Runnable() {
                         @Override
                         public void run() {
                             logger.info("{} has started to roam the wastelands.", name());
                         }
                     }
        );
    }

    public String name() {
        return this.name;
    }
}

Man sieht, dass jede Klasse, die ActiveCreature erweitert, ihren eigenen Kontrollfluss für den Aufruf und die Ausführung der Methoden zum Herumstreifen und Essen hat.

Beispielsweise die Klasse Orc:

public class Orc extends ActiveCreature {

    public Orc(String name) {
        super(name);
    }
}

Nun können wir etliche Kreaturen dieser Art schaffen, sie zum Essen und Herumstreifen auffordern, aber jede von ihnen wird das in Eigenregie (eigener Thread) ausführen.

public class App implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(App.class.getName());

    private static final int NUM_CREATURES = 3;

    public static void main(String[] args) {
        var app = new App();
        app.run();
    }

    @Override
    public void run() {
        List<ActiveCreature> creatures = new ArrayList<>();
        try {
            for (int i = 0; i < NUM_CREATURES; i++) {
                creatures.add(new Orc(Orc.class.getSimpleName() + i));
                creatures.get(i).eat();
                creatures.get(i).roam();
            }
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            logger.error(e.getMessage());
            Thread.currentThread().interrupt();
        } finally {
            for (int i = 0; i < NUM_CREATURES; i++) {
                creatures.get(i).kill(0);
            }
        }
    }
}

Programmausgabe:

09:00:02.501 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 is eating!
09:00:02.501 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 is eating!
09:00:02.501 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 is eating!
09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has finished eating!
09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has finished eating!
09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has started to roam in the wastelands.
09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has finished eating!
09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has started to roam in the wastelands.
09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has started to roam in the wastelands.

Verwendung

  • Wenn asynchrone Aufgaben behandelt werden sollen, ohne dass der Hauptthread blockiert wird, um bessere Performance und Reaktionsfähigkeit zu gewährleisten.
  • Bei asynchronen Interaktionen mit externen Ressourcen.
  • Zur Verbesserung der Reaktionsfähigkeit.
  • Zum Management parallel ablaufender Aufgaben in modularer und wartbarer Art und Weise.

Tutorials

Reale Anwendungen in Java

  • Echtzeit-Handelssysteme mit asynchroner Verarbeitung von Transaktionen.
  • GUIs, bei denen langwierige Arbeiten im Hintergrund ablaufen, ohne dass die Benutzeroberfläche einfriert.
  • Spiele, bei denen Aktualisierungen des Spielstatus oder KI-Berechnungen parallel abgearbeitet werden.

Vor- und Nachteile

Vorteile

  • Reaktionsfähigkeit des Hauptthreads wird verbessert
  • Parallelitätsprobleme sind in den Objekten gekapselt
  • Ermöglicht bessere Codeorganisation und -wartbarkeit.
  • Sorgt für Threadsicherheit und vermeidet Probleme beim gemeinsamen Zugriff auf Zustände.

Nachteile

  • Zusatzaufwand für die Übermittlung von Benachrichtigungen und das Threadmanagement.
  • Nicht für alle Arten von Nebenläufigkeitsproblemen geeignet.

Verwandte Patterns

  • Command: Kapselt Anfragen als Objekte, ähnlich wie Active Object es mit Methodenaufrufen macht.
  • Promise: Bietet einen Weg zur Abfrage von Ergebnissen eines asynchronen Methodenaufrufs, oft mit Active Object kombiniert.
  • Proxy: Active Object kann einen Proxy verwenden, um asynchrone Methodenaufrufe zu behandeln.

Quellen