设计模式---访问者模式(C++实现)
2017-03-21 15:38
375 查看
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。
根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
意图
主要将数据结构和数据操作分离。
解决问题
稳定的数据结构和易变的操作耦合问题
如何解决
在被访问的类里面加一个对外提供接待访问者的接口
优点
1. 符合单一职责原则
2. 优秀的扩展性
3. 灵活性
缺点
1. 具体元素对访问者公布细节,违反了迪米特原则
2. 具体元素变更会更加困难
3.违反了依赖倒置原则,依赖了具体类,没有依赖抽象
使用场景
1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于具体类的操作;
2. 需要对一个对象结构中的对象进行许多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中;
3. 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作;
4. 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
注意事项
访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
UML类图
Visitor(访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
Element(元素):定义一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
ObjectStructure(对象结构):能够枚举它的元素,同时提供一个高层的接口以允许该访问者访问它的元素。
C++实现
//访问者模式
class ConcreteElementA;
class ConcreteElementB;
class Visitor
{
public:
virtual void VisitConcreteElementA(ConcreteElementA* pCA) = 0;
virtual void VisitConcreteElementB(ConcreteElementB* pCB) = 0;
};
class ConcreteVistor1 : public Visitor
{
public :
void VisitConcreteElementA(ConcreteElementA* pCA);
void VisitConcreteElementB(ConcreteElementB* pCB);
};
void ConcreteVistor1::VisitConcreteElementA(ConcreteElementA* pCA)
{
//根据传进来的PCA,可以对ConcreteElementA中的element进行操作
cout <<"ConcreteVistor1:: VisitConcreteElementA" << endl;
}
void ConcreteVistor1::VisitConcreteElementB(ConcreteElementB* pCB)
{
//根据传进来的PCB,可以对ConcreteElementB中的element进行操作
cout << "ConcreteVistor1::VisitConcreteElementB" << endl;
}
class ConcreteVistor2 : public Visitor
{
public :
void VisitConcreteElementA(ConcreteElementA* pCA);
void VisitConcreteElementB(ConcreteElementB* pCB);
};
void ConcreteVistor2::VisitConcreteElementA(ConcreteElementA* pCA)
{
//根据传进来的PCA,可以对ConcreteElementA中的element进行操作
cout << "ConcreteVistor2 :: VisitConcreteElementA" << endl;
}
void ConcreteVistor2::VisitConcreteElementB(ConcreteElementB* pCB)
{
//根据传进来的PCB,可以对ConcreteElementB中的element进行操作
cout << "ConcreteVistor2 :: VisitConcreteElementB" << endl;
}
//Element Object
class Element
{
public :
virtual void Accept(Visitor *pVisitor) = 0;
};
class ConcreteElementA : public Element
{
void Accept(Visitor *pVisitor)
{
pVisitor->VisitConcreteElementA(this);
}
};
class ConcreteElementB : public Element
{
public :
void Accept(Visitor *pVisitor)
{
pVisitor->VisitConcreteElementB(this);
}
};
class ObjectStructure
{
vector<Element *> element;
public :
void Attach(Element* pElement)//添加
{
element.push_back(pElement);
}
void Detach(Element* pElement)//删除
{
vector<Element*>::iterator it = find(element.begin(), element.end(), pElement);
if (it != element.end())
{
element.erase(it);
}
}
void Accept(Visitor* pVisitor)
{
//为每一个element设置visitor,进行对应的操作
for (vector<Element* >::const_iterator it = element.begin(); it != element.end(); ++it)
{
(*it)->Accept(pVisitor);
}
}
};
客户端:
int test_Visitor() //访问者模式
{
ObjectStructure* pObj = new ObjectStructure;
ConcreteElementA* pElementA = new ConcreteElementA;
ConcreteElementB* pElementB = new ConcreteElementB;
pObj->Attach(pElementA);
pObj->Attach(pElementB);
ConcreteVistor1* pVisitor1 = new ConcreteVistor1;
ConcreteVistor2* pVisitor2 = new ConcreteVistor2;
pObj->Accept(pVisitor1);
pObj->Accept(pVisitor2);
if (pVisitor1) delete pVisitor1;
if (pVisitor2) delete pVisitor2;
if (pElementA) delete pElementA;
if (pElementB) delete pElementB;
if (pObj) delete pObj;
system("pause");
return 0;
}
总结
访问者模式的思想如下:首先拥有一个由很多对象构成的对象结构,就是上面代码中的ObjectStructure,这些对象的类都拥有一个Accept方法用来接收访问者对象;问者是一个接口,它拥有一个Visit方法,这个方法对访问到的对象结构中不同类型的元素做出不同的操作;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施Accept方法,在每一个元素的Accept方法中回调访问者的Visit方法,从而使访问者得以处理对象结构的每一个元素。我们就可以针对对象结构设计不同的访问者类来完成不同的操作。
设计模式中经常说的一句话是:发现变化并封装之。是否采用访问者模式,就要看“变化”是什么。访问者模式中,“变化”是具体访问者,其次是对象结构;但是,如果具体元素也会发生改变,就万万不能使用访问者模式,因为这样“牵一发而动全身”,后期的维护性就太差了。
-----其实,我现在理解的不好,希望从大家给点意见,毕竟我没真正遇到过。
根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
意图
主要将数据结构和数据操作分离。
解决问题
稳定的数据结构和易变的操作耦合问题
如何解决
在被访问的类里面加一个对外提供接待访问者的接口
优点
1. 符合单一职责原则
2. 优秀的扩展性
3. 灵活性
缺点
1. 具体元素对访问者公布细节,违反了迪米特原则
2. 具体元素变更会更加困难
3.违反了依赖倒置原则,依赖了具体类,没有依赖抽象
使用场景
1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于具体类的操作;
2. 需要对一个对象结构中的对象进行许多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中;
3. 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作;
4. 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
注意事项
访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
UML类图
Visitor(访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
Element(元素):定义一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
ObjectStructure(对象结构):能够枚举它的元素,同时提供一个高层的接口以允许该访问者访问它的元素。
C++实现
//访问者模式
class ConcreteElementA;
class ConcreteElementB;
class Visitor
{
public:
virtual void VisitConcreteElementA(ConcreteElementA* pCA) = 0;
virtual void VisitConcreteElementB(ConcreteElementB* pCB) = 0;
};
class ConcreteVistor1 : public Visitor
{
public :
void VisitConcreteElementA(ConcreteElementA* pCA);
void VisitConcreteElementB(ConcreteElementB* pCB);
};
void ConcreteVistor1::VisitConcreteElementA(ConcreteElementA* pCA)
{
//根据传进来的PCA,可以对ConcreteElementA中的element进行操作
cout <<"ConcreteVistor1:: VisitConcreteElementA" << endl;
}
void ConcreteVistor1::VisitConcreteElementB(ConcreteElementB* pCB)
{
//根据传进来的PCB,可以对ConcreteElementB中的element进行操作
cout << "ConcreteVistor1::VisitConcreteElementB" << endl;
}
class ConcreteVistor2 : public Visitor
{
public :
void VisitConcreteElementA(ConcreteElementA* pCA);
void VisitConcreteElementB(ConcreteElementB* pCB);
};
void ConcreteVistor2::VisitConcreteElementA(ConcreteElementA* pCA)
{
//根据传进来的PCA,可以对ConcreteElementA中的element进行操作
cout << "ConcreteVistor2 :: VisitConcreteElementA" << endl;
}
void ConcreteVistor2::VisitConcreteElementB(ConcreteElementB* pCB)
{
//根据传进来的PCB,可以对ConcreteElementB中的element进行操作
cout << "ConcreteVistor2 :: VisitConcreteElementB" << endl;
}
//Element Object
class Element
{
public :
virtual void Accept(Visitor *pVisitor) = 0;
};
class ConcreteElementA : public Element
{
void Accept(Visitor *pVisitor)
{
pVisitor->VisitConcreteElementA(this);
}
};
class ConcreteElementB : public Element
{
public :
void Accept(Visitor *pVisitor)
{
pVisitor->VisitConcreteElementB(this);
}
};
class ObjectStructure
{
vector<Element *> element;
public :
void Attach(Element* pElement)//添加
{
element.push_back(pElement);
}
void Detach(Element* pElement)//删除
{
vector<Element*>::iterator it = find(element.begin(), element.end(), pElement);
if (it != element.end())
{
element.erase(it);
}
}
void Accept(Visitor* pVisitor)
{
//为每一个element设置visitor,进行对应的操作
for (vector<Element* >::const_iterator it = element.begin(); it != element.end(); ++it)
{
(*it)->Accept(pVisitor);
}
}
};
客户端:
int test_Visitor() //访问者模式
{
ObjectStructure* pObj = new ObjectStructure;
ConcreteElementA* pElementA = new ConcreteElementA;
ConcreteElementB* pElementB = new ConcreteElementB;
pObj->Attach(pElementA);
pObj->Attach(pElementB);
ConcreteVistor1* pVisitor1 = new ConcreteVistor1;
ConcreteVistor2* pVisitor2 = new ConcreteVistor2;
pObj->Accept(pVisitor1);
pObj->Accept(pVisitor2);
if (pVisitor1) delete pVisitor1;
if (pVisitor2) delete pVisitor2;
if (pElementA) delete pElementA;
if (pElementB) delete pElementB;
if (pObj) delete pObj;
system("pause");
return 0;
}
总结
访问者模式的思想如下:首先拥有一个由很多对象构成的对象结构,就是上面代码中的ObjectStructure,这些对象的类都拥有一个Accept方法用来接收访问者对象;问者是一个接口,它拥有一个Visit方法,这个方法对访问到的对象结构中不同类型的元素做出不同的操作;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施Accept方法,在每一个元素的Accept方法中回调访问者的Visit方法,从而使访问者得以处理对象结构的每一个元素。我们就可以针对对象结构设计不同的访问者类来完成不同的操作。
设计模式中经常说的一句话是:发现变化并封装之。是否采用访问者模式,就要看“变化”是什么。访问者模式中,“变化”是具体访问者,其次是对象结构;但是,如果具体元素也会发生改变,就万万不能使用访问者模式,因为这样“牵一发而动全身”,后期的维护性就太差了。
-----其实,我现在理解的不好,希望从大家给点意见,毕竟我没真正遇到过。
相关文章推荐
- 设计模式---访问者模式(C++实现)
- 设计模式C++实现二十三:访问者模式
- 设计模式C++实现(21)——访问者模式
- 设计模式--访问者模式C++实现
- 设计模式之访问者模式,C++实现
- 设计模式之访问者模式,C++实现
- 常见设计模式的解析和实现(C++)之四-Prototype模式
- 常见设计模式的解析和实现(C++)之十七-State模式
- 常见设计模式的解析和实现(C++)之十五-Observer模式
- Head First 设计模式 C++实现-Strategy(策略模式)
- 设计模式之C++实现 - 工厂模式
- 常见设计模式的解析和实现(C++)之九-Decorator模式
- 常见设计模式的解析和实现(C++)之二十一-完结篇
- 用C++实现设计模式---两个迭代器的传说
- 设计模式---单件(C++版) 比较通用的单件模式(STL实现)
- 常见设计模式的解析和实现(C++)之三-Builder模式
- 常见设计模式的解析和实现(C++)之十三-FlyWeight模式
- 常见设计模式的解析和实现(C++)之六-Adapt模式
- 常见设计模式的解析和实现(C++)之十八-Iterator模式
- 设计模式解析的C++实现