Skip to content

Instantly share code, notes, and snippets.

@FONQRI
Created February 28, 2021 20:11
Show Gist options
  • Save FONQRI/3631f96c6616800abcd22604f4b2be25 to your computer and use it in GitHub Desktop.
Save FONQRI/3631f96c6616800abcd22604f4b2be25 to your computer and use it in GitHub Desktop.
Simple Example for data export with visitor Design pattern
class NormalPoint;
class LoiterPoint;
class ExporterInterface
{
public:
virtual void exportNormalPoint(const NormalPoint* element) const = 0;
virtual void exportLoiterPoint(const LoiterPoint* element) const = 0;
};
/**
* The Component interface declares an `accept` method that should take the base
* visitor interface as an argument.
*/
class BasePoint
{
public:
virtual ~BasePoint()
{}
virtual void exportData(ExporterInterface* visitor) const = 0;
};
/**
* Each Concrete Component must implement the `Accept` method in such a way that
* it calls the visitor's method corresponding to the component's class.
*/
class NormalPoint : public BasePoint
{
/**
* Note that we're calling `visitConcreteComponentA`, which matches the
* current class name. This way we let the visitor know the class of the
* component it works with.
*/
public:
void exportData(ExporterInterface* visitor) const override
{
visitor->exportNormalPoint(this);
}
/**
* Concrete Components may have special methods that don't exist in their base
* class or interface. The Visitor is still able to use these methods since
* it's aware of the component's concrete class.
*/
std::string ExclusiveMethodOfConcreteComponentA() const
{
return "A";
}
};
class LoiterPoint : public BasePoint
{
/**
* Same here: visitConcreteComponentB => ConcreteComponentB
*/
public:
void exportData(ExporterInterface* visitor) const override
{
visitor->exportLoiterPoint(this);
}
std::string SpecialMethodOfConcreteComponentB() const
{
return "B";
}
};
/**
* Concrete Visitors implement several versions of the same algorithm, which can
* work with all concrete component classes.
*
* You can experience the biggest benefit of the Visitor pattern when using it
* with a complex object structure, such as a Composite tree. In this case, it
* might be helpful to store some intermediate state of the algorithm while
* executing visitor's methods over various objects of the structure.
*/
class JsonExporter : public ExporterInterface
{
public:
void exportNormalPoint(const NormalPoint* element) const override
{
std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor1\n";
}
void exportLoiterPoint(const LoiterPoint* element) const override
{
std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor1\n";
}
};
class XmlExporter : public ExporterInterface
{
public:
void exportNormalPoint(const NormalPoint* element) const override
{
std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor2\n";
}
void exportLoiterPoint(const LoiterPoint* element) const override
{
std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor2\n";
}
};
/**
* The client code can run visitor operations over any set of elements without
* figuring out their concrete classes. The accept operation directs a call to
* the appropriate operation in the visitor object.
*/
void ClientCode(std::array<const BasePoint*, 2> components, ExporterInterface* visitor)
{
// ...
for (const BasePoint* comp : components)
{
comp->exportData(visitor);
}
// ...
}
int main()
{
std::array<const BasePoint*, 2> components = {new NormalPoint, new LoiterPoint};
std::cout << "The client code works with all visitors via the base Visitor interface:\n";
JsonExporter* visitor1 = new JsonExporter;
ClientCode(components, visitor1);
std::cout << "\n";
std::cout << "It allows the same client code to work with different types of visitors:\n";
XmlExporter* visitor2 = new XmlExporter;
ClientCode(components, visitor2);
for (const BasePoint* comp : components)
{
delete comp;
}
delete visitor1;
delete visitor2;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment