niedziela, 23 marca 2014

Kompozyt (obiektowy)

Kompozyt (ang. Composite)
Tym razem na warsztat bierzemy wzorzec kompozyt.
Celem wzorca jest składanie obiektów w taki sposób, aby klient widział wiele z nich jako pojedynczy obiekt. Wzorzec ten stosuje się, gdy wygodniej jest korzystać z pewnych operacji dla danego obiektu w ten sam sposób jak dla grupy obiektów, np. rysując na ekranie prymitywy lub obiekty złożone z prymitywów. Zmieniając rozmiar zarówno pojedynczych prymitywów jak i obiektów złożonych z prymitywów (z zachowaniem proporcji).
Najłatwiej przedstawić wzorzec na przykładzie klasy Shape, która jest klasą abstrakcyjną. Po niej dziedziczą klasy przykładowo Rectangle, Square, Ellipse. Jest to dość standardowy przykład. Jednak tworzymy dodatkowo klasę, która będzie się nazywała complexShape. Klasa ta będzie zawierała wskaźniki na dwa Shape-y, które też de facto będą mogły być ComplexShape-ami. I tak, aż do ostatniego shape-a, który będzie prymitywem. Mając klasę complexShape, a w niej wcześniej wspomniane dwa wskaźniki na shape-y, możemy działać na obiekcie complexShape, tak jakby był to typ prosty. Przykładowo wywyołując operacje move() (przesuń), rotate() (obróć), obracamy lub przesuwamy cały obiekt (dwa shape-y), ponieważ complexShape jest tak zakodowany, że wywołuje metody te na swoich wskaźnikach. Czyli ostatecznie przesuwamy bądź obracamy dwa kształty.
Czas na przykład w c++, o którym mówiliśmy. Poniżej umieszczę tylko najważniejsze fragmenty kodu, ponieważ jest on dość długi więc całość będzie dostępna pod linkiem, który zamieszczę pod koniec.
class Shape
{
public:
 std::pair translatedToXY;
 float rotatedByAlpha;
 std::pair rotatedAroundXY;

public:
 Shape(std::pair);
 Shape(void);
 virtual ~Shape(void);

 virtual bool in(std::pair p_pair);
 virtual void translate(std::pair p_translate);
 virtual void rotate(std::pair p_rotationAroundXY, float p_rotationAlpha);

 std::pair getTranslatedToXY(void);
 void setTranslatedToXY(std::pair p_translatedToXY);
 std::pair getRotatedAroundXY();
 void setRotatedAroundXY(std::pair p_rotatedAroundXY);
 float getRotatedByAlpha(void);
 void setRotatedByAlpha(float p_rotatedByAlpha);

 friend class Utils;
};
class Rectangle : public Shape
{
public:
 std::pair xy;
 std::pair xy2;

public:
 Rectangle(std::pair p_xy, std::pair p_xy2);
 Rectangle(void);
 virtual ~Rectangle(void);

 bool in(std::pair p_point);
 std::pair getXy(void);
 void setXy(std::pair p_xy);
 std::pair getXy2(void);
 void setXy2(std::pair p_xy2);

 // friend class Utils;
};
class Ellipse : public Shape
{
public:
 std::pair xy;
 float rx, ry;

public:
 Ellipse(std::pair p_xy, float p_rx, float p_ry);
 Ellipse(void);
 virtual ~Ellipse(void);

 virtual bool in(std::pair p_point);
 std::pair getXy(void);
 void setXy(std::pair p_xy);
 float getRx(void);
 void setRx(float p_rx);
 float getRy(void);
 void setRy(float p_ry);
};
class ComplexShape : public Shape
{
public:
 Shape* shape1;
 Shape* shape2;

 enum Operator {
  Intersection, Union, Difference
 };
 Operator operator_;

 ComplexShape(Shape* shape1, Shape* shape2, Operator operator_);
 ComplexShape(void);
 virtual ~ComplexShape(void);

 Operator getOperator(void);
 void setOperator(Operator operator_);
 virtual bool in(std::pair p);
 Shape* getShape1(void);
 void setShape1(Shape* shape1);
 Shape* getShape2(void);
 void setShape2(Shape* shape2);
 void translate(std::pair xy);
};
Przykładowa metoda translate(), w której widać, że klasa complexShape wywołuje metody translate() na swoich wskaźnikach. Dzięki temu wywołując metode translate() na complexShape-ie przesuwamu cały złożony obiekt.
void ComplexShape::translate(std::pair xy) 
{
 shape1->translate(xy);
 shape2->translate(xy);
}
Link do całego kodu - projekt został skompilowany w środowisku Visual Studio 2013:
LINK
W razie jakiś pytań problemów proszę pisać w komentarzach bądź wysłać emaila. Diagram klas dla wzorca kompozyt.

Brak komentarzy:

Prześlij komentarz