访问者模式
一、简介
1. 定义
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
2. 应用场景
(1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
(2)希望在不修改原有类的前提下,实现对该对象内部的一些操作。
3. 优点
(1)可以通过增加具体访问者类实现新的访问操作,对修改封闭,符合开闭原则。
(2)将不同的访问业务封装到不同的子类中,体现了类的单一职责,同时,相同的对象结构可以支持多个不同的访问者进行访问。
将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
(3)让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。
4. 缺点
(1)在原有对象中增加新的元素类困难。每增加一个新的元素类都意味着要在访问者中增加一个新的操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。
(2)破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。
二、类图
(1)Visitor:接口或者抽象类,它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,因此,访问者模式要求元素的类族要稳定。
(2)ConcreteVisitor1、ConcreteVisitor2:具体的访问类,它需要给出对每一个元素类访问时所产生的具体行为。
(3)Element:元素接口或者抽象类,它定义了一个接受访问者的方法,其意义是指每一个元素都要可以被访问者访问。
(4)ConcreteElementA、ConcreteElementB:具体的元素类,它提供接受访问方法的具体实现。
(5)ObjectStructure:定义当中所说的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素供访问者访问
三、代码示例
#ifndef VISITOR_H #define VISITOR_H #include <QDebug> #include <QList> class ChildBook; class ClassicsBook; class IReader { public: IReader() {}; virtual ~IReader() {}; virtual void read(ChildBook *book) = 0; virtual void read(ClassicsBook *book) = 0; }; class ChildReader : public IReader { public: ChildReader() {}; virtual ~ChildReader() {}; virtual void read(ChildBook *book) { qDebug() << "Child: Children's book is funny!"; }; virtual void read(ClassicsBook *book) { qDebug() << "Child: Classics is boring!"; }; }; class AdultReader : public IReader { public: AdultReader() {}; virtual ~AdultReader() {}; virtual void read(ChildBook *book) { qDebug() << "Adult: Children's book is naive!"; }; virtual void read(ClassicsBook *book) { qDebug() << "Adult: Classics is interesting!"; }; }; class IBook { public: IBook(){}; virtual ~IBook() {}; virtual void rent(IReader *reader) = 0; }; class ChildBook : public IBook { public: ChildBook(){}; virtual ~ChildBook() {}; virtual void rent(IReader *reader) { qDebug() << "Children's book!"; reader->read(this); }; }; class ClassicsBook : public IBook { public: ClassicsBook(){}; virtual ~ClassicsBook() {}; virtual void rent(IReader *reader) { qDebug() << "ClassicsBook!"; reader->read(this); }; }; class Library { public: Library() {}; virtual ~Library() {}; void addBook(IBook *book) { if (nullptr != book) { m_bookList.append(book); } }; void removeBook(IBook *book) { m_bookList.removeOne(book); }; void visit(IReader *reader) { for (auto book : m_bookList) { book->rent(reader); } } private: QList<IBook*> m_bookList; }; #if 1 #define FREE_OBJ(obj) if (nullptr != obj){delete obj; obj = nullptr;} void main() { IReader *child = new ChildReader(); IReader *adult = new AdultReader(); IBook *childBook = new ChildBook(); IBook *classicsBook = new ClassicsBook(); Library *library = new Library; library->addBook(childBook); library->addBook(classicsBook); library->visit(child); library->visit(adult); FREE_OBJ(child); FREE_OBJ(adult); FREE_OBJ(childBook); FREE_OBJ(classicsBook); FREE_OBJ(library); } #endif // 1 #endif // !VISITOR_H