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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

parkseyoung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值