Да, они оба добавляют некоторые функциональные возможности к существующей системе во время выполнения и стараются быть менее восприимчивыми (в хорошем смысле) к динамическим изменениям, но с некоторыми различиями.
Посетитель в первую очередь должен уважатьOCP (а иногда и SRP), чтобы сделать систему более гибкой.Вы можете добавить любого посетителя, которого сможете, по мере развития вашей программы без изменения существующей системы.Однако вам необходимо заранее спроектировать систему .Вы не можете добавить новый класс (или шаблон) посетителя к уже работающей системе и ожидать, что он будет работать без перекомпиляции, повторного тестирования или чего-либо еще.
С другой стороны, вы можете использовать Decorator для обогащения функциональность существующей системы , оборачивая абстрактный базовый класс (который у вас уже есть) в Decorator и предоставляя вашу расширенную функцию в качестве отдельного объекта, чтобы вы могли создавать ее по мере необходимости.Более того, семантически Decorator скорее относится к внешнему виду sth.
Какой из них предпочтительнее?ИМО, ответ на этот вопрос может быть более полезным.Мне не нравится, как декоратор использует базовый класс.Он использует наследование и агрегацию.Если вам нужно изменить этот класс (wrapee), вам придется перекомпилировать всю иерархию / модуль.Но с тех пор это удобно, и вы можете изменить поведение после время разработки .С другой стороны, в шаблоне Visitor мне не нравится идея знать каждый конкретный тип в реализации Visitor.Когда вы добавляете новый тип базового класса, вам также нужно перейти и изменить класс Visitor, чтобы добавить его.Но это полезно, когда вам нужно внедрить код в существующую систему без изменения структуры или если вам нужно разделить задачи в классе (Single-User Resp).
Наконец, что делает Visitor лучше обычного наследования?Зависит.Используя наследование, вы будете более зависимы от подписи интерфейса.Использование Visitor делает ваш класс Visitor зависимым от конкретных классов.Не говоря уже о том, что вы добавляете больше поведений, используя посетителя, не меняя существующую подпись модуля вместо реализации новых интерфейсов в существующем классе.