Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Piotr Szawdyński
Wzorce projektowe

odwiedzający

[wzorzec projektowy] Umożliwia wydzielenie zadań powiązanych logicznie ze sobą do osobnej klasy zwanej odwiedzającym. Odwiedzający może posiadać wiele implementacji zapewniając tym samym możliwość wykonania wielu różnych zadań. Dodawanie nowych zadań odbywa się bez ingerencji w elementy już oprogramowane.

Opis szczegółowy

Odwiedzający (ang. visitor) - wzorzec projektowy, który umożliwia wydzielenie zadań powiązanych logicznie ze sobą do osobnej klasy zwanej odwiedzającym. Odwiedzający może posiadać wiele implementacji zapewniając tym samym możliwość wykonania wielu różnych zadań. Dodawanie nowych zadań odbywa się bez ingerencji w elementy już oprogramowane.

Wady

  • Dodanie nowego elementu, który ma być obsługiwany przez wzorzec wymusza dodanie implementacji obsługi do wszystkich istniejących odwiedzających.
  • Każdy odwiedzający musi mieć dostęp do składowych elementu co oznacza, że każdy element musi mieć publiczny dostęp do używanych składowych obiektu.

Zalety

  • Wymusza dodanie obsługi implementacji do wszystkich istniejących odwiedzających zapewniając tym samym obsługę elementu przez wszystkie zadania.
  • Grupuje funkcjonalność logicznie powiązaną ze sobą w jedną klasę przez co dużo łatwiej jest ją rozwijać i utrzymywać.

Przykład

C/C++
#include <string>
#include <vector>
#include <cstdio>

class CTextElement;
class CCommentElement;

class IVisitor
{
public:
    virtual void visitElement( const CTextElement & element ) = 0;
    virtual void visitElement( const CCommentElement & element ) = 0;
};

class IElement
{
public:
    virtual void acceptVisitor( IVisitor & visitor ) = 0;
};

class CTextElement
    : public IElement
{
public:
    CTextElement( const char * sText )
        : m_sText( sText ? sText
        : "" )
    { }
    const char * getText() const { return m_sText.c_str(); }
    size_t getLength() const { return m_sText.size(); }
protected:
    virtual void acceptVisitor( IVisitor & visitor ) { visitor.visitElement( * this ); }
private:
    std::string m_sText;
};

typedef std::vector < IElement *> VElementsT;

class CCommentElement
    : public IElement
{
public:
    CCommentElement( const char * sText )
        : m_sText( sText ? sText
        : "" )
    { }
    const char * getComment() const { return m_sText.c_str(); }
    size_t getLength() const { return m_sText.size(); }
protected:
    virtual void acceptVisitor( IVisitor & visitor ) { visitor.visitElement( * this ); }
private:
    std::string m_sText;
};

class CDebugPrintElements
    : public IVisitor
{
public:
    virtual void visitElement( const CTextElement & element )
    {
        printf( "Tekst: %s {%d}\n", element.getText(), element.getLength() );
    }
   
    virtual void visitElement( const CCommentElement & element )
    {
        printf( "Komentarz: %s {%d}\n", element.getComment(), element.getLength() );
    }
   
    static void execute( VElementsT & vElements )
    {
        printf( "\n[Debug]\n" );
        CDebugPrintElements visitor;
        for( VElementsT::iterator it = vElements.begin(); it != vElements.end(); ++it )
            ( * it )->acceptVisitor( visitor );
       
    }
};

class CPrintElements
    : public IVisitor
{
public:
    virtual void visitElement( const CTextElement & element )
    {
        printf( "%s\n", element.getText() );
    }
   
    virtual void visitElement( const CCommentElement & element )
    {
        printf( "/* %s */\n", element.getComment() );
    }
   
    static void execute( VElementsT & vElements )
    {
        printf( "\n[Release]\n" );
        CPrintElements visitor;
        for( VElementsT::iterator it = vElements.begin(); it != vElements.end(); ++it )
            ( * it )->acceptVisitor( visitor );
       
    }
};

int main()
{
    VElementsT vElements;
    vElements.push_back( new CTextElement( "To jest tekst" ) );
    vElements.push_back( new CCommentElement( "To jest komentarz" ) );
    vElements.push_back( new CTextElement( "Koniec." ) );
   
    CPrintElements::execute( vElements );
    CDebugPrintElements::execute( vElements );
    for(; !vElements.empty(); vElements.pop_back() )
         delete vElements.back();
   
    return 0;
}
Standardowe wyjście programu:

[Release]
To jest tekst
/* To jest komentarz */
Koniec.

[Debug]
Tekst: To jest tekst {13}
Komentarz: To jest komentarz {17}
Tekst: Koniec. {7}