الگوی بازدیدگر

در برنامه‌نویسی شی گرا و مهندسی نرم‌افزار، الگوی طراحی بازدیدگر راهی برای جدا کردن یک الگوریتم از ساختار شی است که روی آن عمل می‌کند. یک نتیجه عملی این جدایی توانایی برای اضافه کردن عملیات جدید به ساختارهای شی موجود بدون تغییر ساختار آن است که یک راه برای تبعیت از اصل باز/بسته می‌باشد.

به‌طور خلاصه، بازدید کننده اجازه افزودن توابع مجازی به یک خانواده از کلاس‌ها بدون تغییر خود کلاس‌ها را می‌دهد. به جای آن یک کلاس بازدیدگر ایجاد می‌شود فعالیت مخصوص توابع مجازی را پیاده‌سازی می‌کند.

ساختار ویرایش

کلاس UML ویرایش

 
یک نمونه UML کلاس و نمودار توالی الگوی طراحی بازدیدگر.[۱]

مثال C++ ویرایش

کد ویرایش

#include <iostream>
#include <vector>

class AbstractDispatcher; // Forward declare AbstractDispatcher

class File { // Parent class for the elements (ArchivedFile, SplitFile and ExtractedFile)
public:
// This function accepts an object of any class derived from AbstractDispatcher and must be implemented in all derived classes
virtual void accept(AbstractDispatcher &dispatcher) = 0;
};

// Forward declare specific elements (files) to be dispatched
class ArchivedFile;
class SplitFile;
class ExtractedFile;

class AbstractDispatcher { // Declares the interface for the dispatcher
public:
// Declare overloads for each kind of a file to dispatch
virtual void dispatch(ArchivedFile &file) = 0;
virtual void dispatch(SplitFile &file) = 0;
virtual void dispatch(ExtractedFile &file) = 0;
};

class ArchivedFile: public File { // Specific element class #1
public:
// Resolved at runtime, it calls the dispatcher's overloaded function, corresponding to ArchivedFile.
void accept(AbstractDispatcher &dispatcher) override {
dispatcher.dispatch(*this);
}
};

class SplitFile: public File { // Specific element class #2
public:
// Resolved at runtime, it calls the dispatcher's overloaded function, corresponding to SplitFile.
void accept(AbstractDispatcher &dispatcher) override {
dispatcher.dispatch(*this);
}
};

class ExtractedFile: public File { // Specific element class #3
public:
// Resolved at runtime, it calls the dispatcher's overloaded function, corresponding to ExtractedFile.
void accept(AbstractDispatcher &dispatcher) override {
dispatcher.dispatch(*this);
}
};

class Dispatcher: public AbstractDispatcher { // Implements dispatching of all kind of elements (files)
public:
void dispatch(ArchivedFile &) override {
std::cout <<"dispatching ArchivedFile" <<std::endl;
}

void dispatch(SplitFile &) override {
std::cout <<"dispatching SplitFile" <<std::endl;
}

void dispatch(ExtractedFile &) override {
std::cout <<"dispatching ExtractedFile" <<std::endl;
}
};

int main() {
ArchivedFile archivedFile;
SplitFile splitFile;
ExtractedFile extractedFile;

std::vector<File*> files;
files.push_back(&archivedFile);
files.push_back(&splitFile);
files.push_back(&extractedFile);

Dispatcher dispatcher;

for (File* file : files) {
file->accept(dispatcher);
}
}

خروجی ویرایش

dispatching ArchivedFile
dispatching SplitFile
dispatching ExtractedFile

مثال پایتون ویرایش

"""
Visitor pattern example.
"""

from abc import ABCMeta, abstractmethod

NOT_IMPLEMENTED = "You should implement this."

class CarElement:
    __metaclass__ = ABCMeta
    @abstractmethod
    def accept(self, visitor):
        raise NotImplementedError(NOT_IMPLEMENTED)

class Body(CarElement):
    def accept(self, visitor):
        visitor.visitBody(self)

class Engine(CarElement):
    def accept(self, visitor):
        visitor.visitEngine(self)

class Wheel(CarElement):
    def __init__(self, name):
        self.name = name
    def accept(self, visitor):
        visitor.visitWheel(self)

class Car(CarElement):
    def __init__(self):
        self.elements = [
            Wheel("front left"), Wheel("front right"),
            Wheel("back left"), Wheel("back right"),
            Body(), Engine()
        ]

    def accept(self, visitor):
        for element in self.elements:
            element.accept(visitor)
        visitor.visitCar(self)

class CarElementVisitor:
    __metaclass__ = ABCMeta
    @abstractmethod
    def visitBody(self, element):
        raise NotImplementedError(NOT_IMPLEMENTED)
    @abstractmethod
    def visitEngine(self, element):
        raise NotImplementedError(NOT_IMPLEMENTED)
    @abstractmethod
    def visitWheel(self, element):
        raise NotImplementedError(NOT_IMPLEMENTED)
    @abstractmethod
    def visitCar(self, element):
        raise NotImplementedError(NOT_IMPLEMENTED)

class CarElementDoVisitor(CarElementVisitor):
    def visitBody(self, body):
        print("Moving my body.")
    def visitCar(self, car):
        print("Starting my car.")
    def visitWheel(self, wheel):
        print("Kicking my {} wheel.".format(wheel.name))
    def visitEngine(self, engine):
        print("Starting my engine.")

class CarElementPrintVisitor(CarElementVisitor):
    def visitBody(self, body):
        print("Visiting body.")
    def visitCar(self, car):
        print("Visiting car.")
    def visitWheel(self, wheel):
        print("Visiting {} wheel.".format(wheel.name))
    def visitEngine(self, engine):
        print("Visiting engine.")

car = Car()
car.accept(CarElementPrintVisitor())
car.accept(CarElementDoVisitor())
Visiting front left wheel.
Visiting front right wheel.
Visiting back left wheel.
Visiting back right wheel.
Visiting body.
Visiting engine.
Visiting car.
Kicking my front left wheel.
Kicking my front right wheel.
Kicking my back left wheel.
Kicking my back right wheel.
Moving my body.
Starting my engine.
Starting my car.

منابع ویرایش

  1. "The Visitor design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.