Frage

ich unter diese Erklärung auf Wikipedia , insbesondere die C ++ Probe und nicht zu erkennen den Unterschied zwischen nur 3 Klassen definieren, die Schaffung Instanzen und ruft sie, und dieses Beispiel. Was ich sah, war nur zwei andere Klassen in den Prozess platzieren und kann nicht sehen, wo es ein Vorteil sein würde. Jetzt bin ich sicher, dass ich etwas offensichtlich (Holz für die Bäume) bin fehlt? - könnte jemand bitte erklären, das Unternehmen eine definitive realen Welt Beispiel mit


Was ich aus den Antworten weit so machen kann, scheint es mir nur ein komplexer Weg, um dies zu tun:

have an abstract class: MoveAlong with a virtual method: DoIt()
have class Car inherit from MoveAlong, 
     implementing DoIt() { ..start-car-and-drive..}
have class HorseCart inherit from MoveAlong, 
     implementing DoIt() { ..hit-horse..}
have class Bicycle inherit from MoveAlong, 
     implementing DoIt() { ..pedal..}
now I can call any function taking MoveAlong as parm 
passing any of the three classes and call DoIt
Isn't this what Strategy intents? (just simpler?)

[Edit-Update] Die Funktion, die ich oben beziehe sich mit einer anderen Klasse ersetzt, in der MoveAlong Attribut wäre, die nach festgelegt ist muss auf der Grundlage des Algorithmus in dieser neuen Klasse implementiert. (Ähnlich wie in der akzeptierten Antwort demonstriert.)


[Edit-Update] Fazit

Die Strategie Muster hat es Anwendungen, aber ich bin ein überzeugter Anhänger KISS, und würde einfacher und weniger obfuscatory Techniken neigen. Meistens da möchte ich leicht wartbaren Code weitergeben (und ‚cos I wahrscheinlich derjenige, der die Änderungen vornehmen müssen, um wieder!).

War es hilfreich?

Lösung

Der Punkt ist, Algorithmen in Klassen zu trennen, die zur Laufzeit eingesteckt werden können. Zum Beispiel, sagen wir, Sie haben eine Anwendung, die eine Uhr umfasst. Es gibt viele verschiedene Möglichkeiten, wie Sie eine Uhr zeichnen können, aber zum größten Teil ist die zugrunde liegende Funktionalität gleich. So können Sie eine Uhr Display-Schnittstelle erstellen:

class IClockDisplay
{
    public:
       virtual void Display( int hour, int minute, int second ) = 0;
};

Dann haben Sie Ihre Clock-Klasse, mit einem Timer angeschlossen ist und aktualisiert die Anzeige der Uhrzeit einmal pro Sekunde. Also würden Sie so etwas wie:

class Clock
{
   protected:
      IClockDisplay* mDisplay;
      int mHour;
      int mMinute;
      int mSecond;

   public:
      Clock( IClockDisplay* display )
      {
          mDisplay = display;
      }

      void Start(); // initiate the timer

      void OnTimer()
      {
         mDisplay->Display( mHour, mMinute, mSecond );
      }

      void ChangeDisplay( IClockDisplay* display )
      {
          mDisplay = display;
      }
};

Dann zur Laufzeit Sie Ihre Uhr mit der richtigen Anzeigeklasse instanziiert. das heißt Sie ClockDisplayDigital, ClockDisplayAnalog, ClockDisplayMartian alle zur Durchführung des IClockDisplay Schnittstelle haben.

So können Sie später jede Art von neuer Uhrzeitanzeige hinzufügen können, indem Sie eine neue Klasse erstellen, ohne sie mit Ihrer Klasse Clock zu Chaos mit und ohne Verfahren außer Kraft zu setzen, die chaotisch sein können, zu pflegen und zu debuggen.

Andere Tipps

In Java verwenden Sie eine Chiffre Eingangsstrom wie so zu entschlüsseln:

String path = ... ;
InputStream = new CipherInputStream(new FileInputStream(path), ???);

Aber der Verschlüsselungsstrom hat keine Kenntnis davon, welche Verschlüsselungsalgorithmus Sie beabsichtigen, zu verwenden oder die Blockgröße, padding Strategie etc ... Neue Algorithmen werden die ganze Zeit so hinzugefügt werden hartzucodieren sie nicht praktikabel ist. Stattdessen gehen wir in einer Cipher Strategieobjekt , ihm zu sagen, wie die Entschlüsselung auszuführen ...

String path = ... ;
Cipher strategy = ... ;
InputStream = new CipherInputStream(new FileInputStream(path), strategy);

Generell Sie die Strategie-Muster verwenden, jedes Mal, wenn ein beliebiges Objekt haben, die weiß, was es tun muss, aber nicht wie , es zu tun. Ein weiteres gutes Beispiel ist das Layout Manager in Swing, obwohl in diesem Fall tut es ganz so gut funktionieren, finden Sie unter Total GridBag für eine amüsante Illustration.

NB: Es gibt zwei Muster bei der Arbeit hier, wie die Verpackung von Strömen in Strömen ist ein Beispiel für Decorator .

Es gibt einen Unterschied zwischen Strategie und Entscheidung / Wahl. Die meiste Zeit eine würden wir Entscheidungen / Entscheidungen in unserem Code werden Handhabung und realisieren sie, wenn () / Schalter () Konstrukte verwenden. Strategie-Muster ist nützlich, wenn es notwendig ist, die Logik / Algorithmus aus der Nutzung zu entkoppeln.

Als Beispiel Denken Sie an einen Abfragemechanismus, wo verschiedene Benutzer für Ressourcen / Updates prüfen würde. Jetzt möchten wir einige der priveliged Benutzer mit einer schnelleren Durchlaufzeit oder mit mehr Details mitzuteilen. Essentailly die Logik Änderungen auf Benutzerrollen basiert verwendet. Strategie macht Sinn, von einem Design / Architektur Aussichtspunkt, auf den unteren Ebenen der Granularität sollte es immer in Frage gestellt werden.

Die Strategie Muster können Sie polimorphism nutzen, ohne Ihre Hauptklasse erstreckt. Im Wesentlichen sind Sie setzen alle variablen Teile in der Strategie-Schnittstelle und Implementierungen und die Hauptklasse Delegierten zu ihnen. Wenn Ihr Hauptziel nur eine Strategie verwendet, es ist fast das gleiche wie mit einer abstrakten (rein virtueller) Methode und verschiedene Implementierungen in jeder Unterklasse.

Die Strategie Ansatz bietet einige Vorteile:

  • Sie können Strategie zur Laufzeit ändern - vergleichen Sie dies den Klassentyp zur Laufzeit zu ändern, die viel schwieriger, Compiler spezifisch und nicht für nicht-virtuelle Methoden
  • ist
  • eine Hauptklasse können mehrere Strategien verwendet werden, die Sie sie auf vielfältige Weise rekombinieren können. Betrachten wir eine Klasse, die einen Baum geht und wertet eine Funktion basierend auf den einzelnen Knoten und dem aktuellen Ergebnis. Sie können eine Walking-Strategie (depth-first oder Breite beginn) haben und Berechnungsstrategie (einige Funktors - das heißt ‚zählen positive Zahlen‘ oder ‚Summe‘). Wenn Sie keine Strategien verwenden, müssen Sie Unterklasse für jede Kombination von Geh- / Berechnung implementieren.
  • Code ist leichter zu pflegen als modifizierende oder Strategie zu verstehen, nicht benötigen Sie die ganze Hauptaufgabe
  • verstehen

Der Nachteil ist, dass in vielen Fällen die Strategie Muster zuviel des Guten ist - der Schalter / Fall-Operator ist es für einen Grund. Betrachten Sie beginnen mit einfachen Steuerflussrechnungen (Schalter / Fall oder wenn) nur dann, wenn notwendig, Umzug in Klassenhierarchie und wenn Sie mehr als eine Dimension der Variabilität, Extrakt Strategien aus ihm heraus. Funktionszeiger fallen irgendwo in der Mitte dieses Kontinuums.

Empfohlene Lektüre:

Eine Möglichkeit, dies zu betrachten ist, wenn Sie eine Vielzahl von Aktionen haben Sie ausführen möchten, und diese Aktionen werden zur Laufzeit bestimmt. Wenn Sie eine Hash-Tabelle oder Wörterbuch von Strategien erstellen, könnten Sie diese Strategien abrufen, die Werte oder Parameter befehlen entsprechen. Sobald Ihre Teilmenge ausgewählt ist, können Sie einfach die Liste der Strategien durchlaufen und nacheinander auszuführen.

Ein konkretes Beispiel wäre die Berechnung der Gesamt eines Auftrages. Ihre Parameter oder Befehle würden Basispreis, lokale Steuern, Kurtaxe, staatliche Steuer, Boden Versand und Coupon Rabatt werden. Die Flexibilität ins Spiel kommen, wenn Sie die Änderung von Aufträgen verarbeiten - einige Staaten nicht Umsatzsteuer haben, während andere Aufträge benötigen einen Gutschein beantragen. Sie können dynamisch die Reihenfolge der Berechnungen zuweisen. Solange Sie für alle Ihre Berechnungen berücksichtigt haben, können Sie alle Kombinationen ohne Neukompilierung aufzunehmen.

Dieses Entwurfsmuster ermöglicht kapseln Algorithmen in Klassen.

Die Klasse, die die Strategie, die Client-Klasse verwendet, wird aus dem Algorithmus Implementierung entkoppelt. Sie können die Algorithmen Implementierung ändern oder neuen Algorithmus hinzugefügt werden, ohne den Client zu modifizieren. Dies kann auch dynamisch erfolgen: der Client den Algorithmus wählen kann er verwenden wird.

Ein Beispiel eine Anwendung vorstellen, die ein Bild in einer Datei speichern muss; das Bild kann in verschiedenen Formaten (PNG, JPG ...) gespeichert werden. Die Codierungsalgorithmen werden alle in verschiedenen Klassen implementiert werden, teilen die gleiche Schnittstelle. Die Client-Klasse wählt man je nach Benutzerpräferenz.

In der Wikipedia Beispiel können diese Instanzen in eine Funktion übergeben werden, die nicht zu kümmern hat, welche Klasse diese Instanzen gehören. Die Funktion ruft nur execute auf das Objekt übergeben, und wissen, dass das Richtige passieren wird.

Ein typisches Beispiel für das Strategie-Muster ist, wie Dateien in Unix arbeiten. Bei einem Dateideskriptor, können Sie es lesen, um es zu schreiben, abfragen es, suchen Sie darauf senden ioctls ihm usw., ohne zu wissen, ob Sie mit einer Datei, Verzeichnis, Pipe, Socket-Gerät zu tun hat usw. (natürlich einige Operationen, wie suchen, arbeitet nicht an Rohren und Steckdosen. Aber liest und schreibt in diesen Fällen werden gut funktionieren.)

Das bedeutet, dass Sie generischen Code schreiben können all diese verschiedenen Arten von „Dateien“ zu handhaben, ohne gesonderten Code schreiben zu müssen mit Dateien im Vergleich zu Verzeichnissen usw. Der Unix-Kernel kümmert mich um die Übertragung die Anrufe an den richtigen Code zu beschäftigen.

Nun sind diese Strategie Muster wie im Kernel-Code verwendet, aber man hat nicht angegeben, dass es Benutzercode sein mußte, nur ein Beispiel aus der Praxis. : -)

Strategie-Muster funktioniert auf einfache Idee heißt „Favor Zusammensetzung über Vererbung“, so dass Strategie / Algorithmus kann zur Laufzeit geändert werden. Zur Veranschaulichung lassen Sie uns ein Beispiel nehmen, wo in wir verschiedene Botschaften auf der Grundlage seiner Art verschlüsseln müssen z.B. Mailmessage, ChatMessage etc.

class CEncryptor
{
    virtual void encrypt () = 0;
    virtual void decrypt () = 0;
};
class CMessage
{
private:
    shared_ptr<CEncryptor> m_pcEncryptor;
public:
    virtual void send() = 0;

    virtual void receive() = 0;

    void setEncryptor(cost shared_ptr<Encryptor>& arg_pcEncryptor)
    {
        m_pcEncryptor =  arg_pcEncryptor;
    }

    void performEncryption()
    {
        m_pcEncryptor->encrypt();
    }
};

Jetzt zur Laufzeit können Sie verschiedene Nachrichten instanziiert von CMessage geerbt (wie CMailMessage: public CMessage) mit unterschiedlichen Verschlüssler (wie CDESEncryptor: public CEncryptor)

CMessage *ptr = new CMailMessage();
ptr->setEncryptor(new CDESEncrypto());
ptr->performEncryption();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top