Посетитель | |
---|---|
Visitor | |
Тип | поведенческий |
Назначение | не изменяя основного класса, добавить в него новые операции. |
Структура |
![]() |
Применяется в случаях | когда необходимо для ряда классов сделать похожую (одну и ту же) операцию. |
Плюсы | |
Минусы |
|
Описан в Design Patterns | Да |
Посетитель (англ. visitor) — поведенческий шаблон проектирования, описывающий операцию, которая выполняется над объектами других классов. При изменении visitor нет необходимости изменять обслуживаемые классы.
Шаблон демонстрирует классический приём восстановления информации о потерянных типах, не прибегая к понижающему приведению типов при помощи двойной диспетчеризации.
Необходимо сделать какие-то несвязные операции над рядом объектов, но нужно избежать загрязнения их кода. И нет возможности или желания запрашивать тип каждого узла и осуществлять приведение указателя к правильному типу, прежде чем выполнить нужную операцию.
Над каждым объектом некоторой структуры выполняется одна или более операций. Нужно определить новую операцию, не изменяя классы объектов.
Для независимости посетитель имеет отдельную иерархию. Структуры имеют некий интерфейс взаимодействия.
Если есть вероятность изменения иерархии обслуживаемого класса, либо она будет нестабильной или открытый интерфейс достаточно эффективен для доступа шаблона, то его использование будет вредоносным.
Создается базовый класс Visitor
с методами visit()
для каждого подкласса родительского Element
. Добавьте метод accept(visitor)
в иерархию Element. Для каждой операции, которая должна выполняться для объектов Element
, создайте производный от Visitor
класс. Реализации метода visit()
должны использовать открытый интерфейс класса Element
. В результате: клиенты создают объекты Visitor
и передают их каждому объекту Element
, вызывая accept()
.
Шаблон следует использовать, если:
Преимущества:
Visitor
;Visitor
может запоминать в себе какое-то состояние по ходу обхода контейнера.Недостатки:
accept(Visitor)
в иерархию «элемент».Visitor
и определите методы visit()
для каждого типа элемента.Visitor
для каждой операции, исполняемой над элементами.Visitor
и передаёт его в вызываемый метод accept().
#include <iostream>
#include <string>
class Foo;
class Bar;
class Baz;
class Visitor {
public:
virtual void visit(Foo &ref) = 0;
virtual void visit(Bar &ref) = 0;
virtual void visit(Baz &ref) = 0;
virtual ~Visitor() = default;
};
class Element {
public:
virtual void accept(Visitor &v) = 0;
virtual ~Element() = default;
};
class Foo : public Element {
public:
void accept(Visitor &v) override {
v.visit(*this);
}
};
class Bar : public Element {
public:
void accept(Visitor &v) override {
v.visit(*this);
}
};
class Baz : public Element {
public:
void accept(Visitor &v) override {
v.visit(*this);
}
};
class GetType : public Visitor {
public:
std::string value;
public:
void visit(Foo &ref) override {
value = "Foo";
}
void visit(Bar &ref) override {
value = "Bar";
}
void visit(Baz &ref) override {
value = "Baz";
}
};
int main() {
Foo foo;
Bar bar;
Baz baz;
Element *elements[] = {&foo, &bar, &baz};
for (auto elem : elements) {
GetType visitor;
elem->accept(visitor);
std::cout << visitor.value << std::endl;
}
return 0;
}
public class Demo {
public static void main ( String [] args ) {
Point p = new Point2d( 1, 2 );
Visitor v = new Chebyshev();
p.accept( v );
System.out.println( p.getMetric() );
}
}
interface Visitor {
public void visit ( Point2d p );
public void visit ( Point3d p );
}
abstract class Point {
public abstract void accept ( Visitor v );
private double metric = -1;
public double getMetric () {
return metric;
}
public void setMetric ( double metric ) {
this.metric = metric;
}
}
class Point2d extends Point {
public Point2d ( double x, double y ) {
this.x = x;
this.y = y;
}
public void accept ( Visitor v ) {
v.visit( this );
}
private double x;
public double getX () { return x; }
private double y;
public double getY () { return y; }
}
class Point3d extends Point {
public Point3d ( double x, double y, double z ) {
this.x = x;
this.y = y;
this.z = z;
}
public void accept ( Visitor v ) {
v.visit( this );
}
private double x;
public double getX () { return x; }
private double y;
public double getY () { return y; }
private double z;
public double getZ () { return z; }
}
class Euclid implements Visitor {
public void visit ( Point2d p ) {
p.setMetric( Math.sqrt( p.getX()*p.getX() + p.getY()*p.getY() ) );
}
public void visit ( Point3d p ) {
p.setMetric( Math.sqrt( p.getX()*p.getX() + p.getY()*p.getY() + p.getZ()*p.getZ() ) );
}
}
class Chebyshev implements Visitor {
public void visit ( Point2d p ) {
double ax = Math.abs( p.getX() );
double ay = Math.abs( p.getY() );
p.setMetric( ax>ay ? ax : ay );
}
public void visit ( Point3d p ) {
double ax = Math.abs( p.getX() );
double ay = Math.abs( p.getY() );
double az = Math.abs( p.getZ() );
double max = ax>ay ? ax : ay;
if ( max<az ) max = az;
p.setMetric( max );
}
}
public static class Demo
{
private static void Main()
{
Point p = new Point2D(1, 2);
IVisitor v = new Chebyshev();
p.Accept(v);
Console.WriteLine(p.Metric);
}
}
internal interface IVisitor
{
void Visit(Point2D p);
void Visit(Point3D p);
}
internal abstract class Point
{
public double Metric { get; set; } = -1;
public abstract void Accept(IVisitor visitor);
}
internal class Point2D : Point
{
public Point2D(double x, double y)
{
X = x;
Y = y;
}
public double X { get; }
public double Y { get; }
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
internal class Point3D : Point
{
public Point3D(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
public double X { get; }
public double Y { get; }
public double Z { get; }
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
internal class Euclid : IVisitor
{
public void Visit(Point2D p)
{
p.Metric = Math.Sqrt(p.X*p.X + p.Y*p.Y);
}
public void Visit(Point3D p)
{
p.Metric = Math.Sqrt(p.X*p.X + p.Y*p.Y + p.Z*p.Z);
}
}
internal class Chebyshev : IVisitor
{
public void Visit(Point2D p)
{
var ax = Math.Abs(p.X);
var ay = Math.Abs(p.Y);
p.Metric = ax > ay ? ax : ay;
}
public void Visit(Point3D p)
{
var ax = Math.Abs(p.X);
var ay = Math.Abs(p.Y);
var az = Math.Abs(p.Z);
var max = ax > ay ? ax : ay;
if (max < az) max = az;
p.Metric = max;
}
}
<?php
interface Visitor {
public function visit ( Point $point );
}
abstract class Point {
public abstract function accept ( Visitor $visitor );
private $_metric = -1;
public function getMetric () {
return $this->_metric;
}
public function setMetric ( $metric ) {
$this->_metric = $metric;
}
}
class Point2d extends Point {
public function __construct ( $x, $y ) {
$this->_x = $x;
$this->_y = $y;
}
public function accept ( Visitor $visitor ) {
$visitor->visit( $this );
}
private $_x;
public function getX () { return $this->_x; }
private $_y;
public function getY () { return $this->_y; }
}
class Point3d extends Point {
public function __construct ( $x, $y, $z ) {
$this->_x = $x;
$this->_y = $y;
$this->_z = $z;
}
public function accept ( Visitor $visitor ) {
$visitor->visit( $this );
}
private $_x;
public function getX () { return $this->_x; }
private $_y;
public function getY () { return $this->_y; }
private $_z;
public function getZ () { return $this->_z; }
}
class Euclid implements Visitor {
public function visit ( Point $p ) {
if($p instanceof Point2d)
$p->setMetric( sqrt( $p->getX()*$p->getX() + $p->getY()*$p->getY() ) );
elseif( $p instanceof Point3d)
$p->setMetric( sqrt( $p->getX()*$p->getX() + $p->getY()*$p->getY() + $p->getZ()*$p->getZ() ) );
}
}
class Chebyshev implements Visitor {
public function visit ( Point $p ) {
if($p instanceof Point2d){
$ax = abs( $p->getX() );
$ay = abs( $p->getY() );
$p->setMetric( $ax>$ay ? $ax : $ay );
}
elseif( $p instanceof Point3d){
$ax = abs( $p->getX() );
$ay = abs( $p->getY() );
$az = abs( $p->getZ() );
$max = $ax>$ay ? $ax : $ay;
if ( $max<$az ) $max = $az;
$p->setMetric( $max );
}
}
}
function start(){
$p = new Point2d( 1, 2 );
$v = new Chebyshev();
$p->accept( $v );
echo ( $p->getMetric() );
};
start();
from abc import ABCMeta, abstractmethod
class Spy(metaclass=ABCMeta):
"""
Шпион - посетитель
"""
@abstractmethod
def visit(self, facility) -> None:
"""
Посетить военный объект
"""
pass
class MilitaryFacility(metaclass=ABCMeta):
"""
Военный объект - посещаемый объект
"""
@abstractmethod
def accept(self, spy: Spy) -> None:
"""
Принять шпиона-посетителя
"""
pass
class MilitaryBase(MilitaryFacility):
"""
Военная база подводного флота
"""
def __init__(self) -> None:
self._secret_draftings = 1
self._nuclear_submarines = 1
def __repr__(self) -> str:
return 'На военной базе находится {} атомных подводных лодок и {} секретных чертежей'.format(
self._nuclear_submarines, self._secret_draftings
)
def accept(self, spy: Spy) -> None:
spy.visit(self)
def remove_secret_draftings(self) -> None:
if self._secret_draftings:
self._secret_draftings -= 1
def remove_nuclear_submarine(self) -> None:
if self._nuclear_submarines:
self._nuclear_submarines -= 1
class Headquarters(MilitaryFacility):
"""
Центральный штаб армии
"""
def __init__(self) -> None:
self._generals = 3
self._secret_documents = 2
def __repr__(self) -> str:
return 'В штабе находится {} генералов и {} секретных документов'.format(
self._generals, self._secret_documents
)
def accept(self, spy: Spy) -> None:
spy.visit(self)
def remove_general(self) -> None:
if self._generals:
self._generals -= 1
def remove_secret_documents(self) -> None:
if self._secret_documents:
self._secret_documents -= 1
class JamesBond(Spy):
"""
Конкретный шпион
"""
def visit(self, facility: MilitaryFacility) -> None:
if isinstance(facility, MilitaryBase): # Джеймс Бонд посещает военную базу
facility.remove_secret_draftings() # похищает секретные чертежи
facility.remove_nuclear_submarine() # и напоследок взрывает атомную подводную лодку
elif isinstance(facility, Headquarters): # Джеймс Бонд посещает штаб
facility.remove_general() # ...
facility.remove_general() # ...
facility.remove_secret_documents() # ...
facility.remove_general() # последовтельно уничтожает всех генералов
facility.remove_secret_documents() # и похищает все секретные документы
if __name__ == '__main__':
base = MilitaryBase()
hq = Headquarters()
spy = JamesBond()
base.accept(spy)
hq.accept(spy)
print('OUTPUT:') # посещения Джеймса Бонда были действительно разрушительными
print(base)
print(hq)
'''
OUTPUT:
На военной базе находится 0 атомных подводных лодок и 0 секретных чертежей
В штабе находится 0 генералов и 0 секретных документов
'''
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .