Wzorce projektowe (21)

Autor: Damian Chodorek • Opublikowany: 24 lipca 2015 • Kategoria: kursy, wzorce projektowe

Stan.

Stan to wzorzec obiektowy. Umożliwia zmianę zachowania obiektu poprzez zmianę jego stanu wewnętrznego, ułatwia rozbudowę obiektu o nowe stany.

Klasy

class State{/*
klasa abstrakcyjna, po której dziedziczą wszystkie stany
*/};

// klasy konkretnych stanów
class ConcreteState1: public State{};
class ConcreteState2: public State{};
class ConcreteState3: public State{};

class StateContext{/*
klasa ustawiająca któryś z konkretnych stanów; jej metody wywołują metody stanu
*/};

class Client{/*
komunikuje się tylko z interfejsem StateContext
*/};

Etapy działania

  1. Klient tworzy obiekt StateContext.
  2. Ustawia obiektowi konkretny stan.
  3. Wykonuje metody i zmienia stan jeśli zajdzie potrzeba.

Konsekwencje

  • dane, które mają być trwałe muszą zostać zapisane do obiektu głównego, gdyż stan jest obiektem tymczasowym,
  • dane tymczasowe powinny być trzymane w obiekcie stanu do czasu uzyskania kompletnych informacji, a wtedy powinny przekazać je do obiektu głównego,
  • bardzo łatwo jest dodawać nowe stany.

Przykład

#include <string>
#include <iostream>

using namespace std;

///klasy pomocnicze
class Point
{
  public:
    int x,y;
};

class Rectangle
{
  public:
    void set(Point p1, Point p2)
    {
        begin=p1;
        end=p2;

        cout<<"Wybrano zaznaczenie od: "<<p1.x<<","<<p1.y<<
         " do: "<<p2.x<<","<<p2.y<<endl;
    }

  private:
    Point begin, end;
};

///klasa stanu
class AbstractTool {
 public:
    virtual void MoveTo(const Point& inP) = 0;
    virtual void MouseDown(const Point& inP) = 0;
    virtual void MouseUp(const Point& inP) = 0;

    virtual ~AbstractTool(){}
};

///konkretne stany
class PenTool : public AbstractTool
{
  public:
    PenTool() : mMouseIsDown(false) {}
   
    virtual void MoveTo(const Point& inP)
    {
        if(mMouseIsDown) 
        {
            DrawLine(mLastP, inP);
        }
         
        mLastP = inP;
    }

    virtual void MouseDown(const Point& inP) 
    {
        mMouseIsDown = true;
        mLastP = inP;
    }

    virtual void MouseUp(const Point& inP) 
    { 
        mMouseIsDown = false;
    }

  private:
    bool mMouseIsDown;
    Point mLastP;

    void DrawLine(Point p1, Point p2)
    {
        cout<<"Narysowana linia od: "<<p1.x<<","<<p1.y<<
          " do: "<<p2.x<<","<<p2.y<<endl;
    }
 };
 
class SelectionTool : public AbstractTool
{
  public:
       SelectionTool() : mMouseIsDown(false) {}
   
    virtual void MoveTo(const Point& inP) 
    {
        if(mMouseIsDown) 
        {
             mSelection.set(mLastP, inP);
        }
    }

    virtual void MouseDown(const Point& inP) 
    {
        mMouseIsDown = true;
        mLastP = inP;
        mSelection.set(mLastP, inP);
    }

    virtual void MouseUp(const Point& inP) 
    { 
        mMouseIsDown = false;
    }

  private:
    bool mMouseIsDown;
    Point mLastP;
    Rectangle mSelection;
 };

///Kontekst stanu

class DrawingController 
{
  public:
    DrawingController() :currentTool(NULL) { selectPenTool(); } //na początek wybieramy stan domyślny
    void MoveTo(const Point& inP) {currentTool->MoveTo(inP); }
    void MouseDown(const Point& inP) {currentTool->MouseDown(inP); }
    void MouseUp(const Point& inP) {currentTool->MouseUp(inP); }
 
    void selectPenTool() 
    {
        delete currentTool;
        currentTool=new PenTool();
    }
 
    void selectSelectionTool() 
    {
        delete currentTool;
        currentTool=new SelectionTool();
    }
 
  private:
    AbstractTool* currentTool;
 };


int main(int argc, const char* argv[])
{
    DrawingController dc;

    Point point;
    point.x=0;
    point.y=0;

    dc.MouseDown(point);

    point.x=20;
    point.y=20;
    dc.MoveTo(point);
    dc.MouseUp(point);

    dc.selectSelectionTool();
  
    point.x=0;
    point.y=0;
    dc.MouseDown(point);

    point.x=20;
    point.y=20;
    dc.MoveTo(point);
    dc.MouseUp(point);
}

Kolejna część już wkrótce.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.