当前位置: 代码迷 >> 综合 >> 设计模式(二) 访问者模式 Vistor
  详细解决方案

设计模式(二) 访问者模式 Vistor

热度:92   发布时间:2023-11-02 18:12:48.0

在软件开发中,经常需要用到多态,继承等机制,下面是很常见的一段代码

class Brand
{
public:virtual void productShoe() = 0;
}class Nike : public Brand
{
public:virtual void productShoe(){//createAj1();}
};class Adidas : public Brand
{
public:virtual void productShoe(){//createYeezy();}
};

基类品牌有一个生产鞋子的方法,子类继承并重写(override)。这种类的层次结构中常常会需要增加新的行为,比如我们需要生产衣服,我们一般会这么改。

class Brand
{
public:virtual void productShoe() = 0;virtual void productClothes() = 0;
}class Nike : public Brand
{
public:virtual void productShoe() override{//createAj1();}virtual void productClothes(){//createNSW();}
};class Adidas : public Brand
{
public:virtual void productShoe(){//createYeezy();}virtual void productClothes(){//createOriginals();}
};

问题来了,这样改会更改抽象基类,但是抽象应该是稳定的(依赖倒置),并且也不符合开放封闭原则(对修改封闭)。

这样,我们的访问者模式就应运而出了!

(当然,在这里我们可以默认这整个类的层次结构是不会改变的,也就是就这么几个子类)

访问者模式是为了解决行为变化的,和命令者模式(command)一起归为行为变化模式。

我们可以将代码用访问者模式重构成如下代码

class Visitor;class Brand
{
public:virtual void accept(Visitor& visitor) = 0;
}class Nike : public Brand
{
public:virtual void accept(Visitor& visitor){visitor.visitNike(*this);}
};class Adidas : public Brand
{
public:virtual void accept(Visitor& visitor){visitor.visitAdidas(*this);}
};class Visitor
{
public:virtual void visitNike(Nike& nike) = 0;virtual void visitAdidas(Adidas& adidas) = 0;
};class ShoeVisitor : public Visitor
{
public:virtual void visitNike(Nike& nike){//nike.createAj();};virtual void visitAdidas(Adidas& adidas){//adidas.createYeezy();}
};

这样,我们调用的时候只需这样:

Adidas adidas;
ShoeVisitor visitor;
adidas.accept(visitor);    //double dispatch

注意,注释的地方的double dispatch的含义是两次多态辨析,意思是这里使用了两次多态调用。

首先accept方法是继承自基类Brand,其次accept里面的visitAdidas的方法也是来自原基类Visitor的虚函数,这又是一次多态。

这样,我们的功能(行为)就可以都写在visitNike里面,而不必破坏原有的类结构。

缺点:

我们从上面代码可以看出,基类Visitor是一个抽象基类,抽象就应该是稳定的,而基类Visitor中的两个方法都是依赖于Brand的两个子类Nike和Adidas,这就说明这个体系中,Brand和Brand的两个子类也应该是稳定的,然而这个条件很难达到。

 

ps:一般这个模式都是运用在一种固定的类结构中(比如树形结构中),对不同的对象(不同类型的树节点)进行不同的操作(可以是处理数据节点,也可以是遍历父节点),这里子类的类型必须要是稳定的(树节点的类型是稳定的)。