1. 程式人生 > 程式設計 >java設計模式系列之訪問者模式

java設計模式系列之訪問者模式

寫這篇文章之前,我也看了十幾篇網路大牛寫的訪問者設計模式的文章,都說這個訪問者模式是最複雜的一個,但是我覺得跟其他的設計模式並沒有太多的不同,因此自己整理了一下,相信大多數人都能看懂。

一、認識訪問者模式

1、概念

封裝一些作用於某種資料結構中的各元素的操作,它可以在不改變這個資料結構的前提下,定義作用於這些元素的新操作。

如何來理解呢?舉個例子來說吧,假如我們都玩過王者榮耀。每個英雄都有三個基本的技能,但是不同的玩家操作英雄技能實現的方式是不一樣的。比如說你玩韓信只能送人頭,夢淚玩韓信那就是百戰百勝。

在這個例子中,莊周和甄姬的三個基本的技能是不變的,但是訪問者模式能夠在這三個技能之上實現一些不同的效果。我們可以畫一張類圖進一步去了解它。

2、類圖

相信說這種模式比較複雜的都是因為其類圖吧,不過我們為每一個模組進行著色之後就能發現其實沒那麼麻煩。以上類圖一共涉及到了六個角色:

(1) Vistor(抽象訪問者):為該物件結構中具體元素角色宣告一個訪問操作介面。就好像是王者榮耀裡面不同的玩家。

(2) ConcreteVisitor(具體訪問者):每個具體訪問者都實現了Vistor中定義的操作。就好比是具體某一個玩家。

(3) Element(抽象元素):定義了一個accept操作,以Visitor作為引數。可以類比成王者裡面英雄的模板。

(4) ConcreteElement(具體元素):實現了Element中的accept()方法,呼叫Vistor的訪問方法以便完成對一個元素的操作。可以表示為具體某一個英雄,好比是莊周和甄姬。

(5) ObjectStructure(物件結構):可以是組合模式,也可以是集合;能夠列舉它包含的元素;提供一個介面,允許Vistor訪問它的元素。也就是莊周和甄姬允許外界訪問的元素。

有了這個概念,下面我們就可以使用程式碼來分析一下了。

二、程式碼實現

第一步:定義抽象元素(英雄的模板)

public abstract class Hero {
	//英雄可以接受玩家的訪問,讓玩家來操作
	public abstract void accept(Player visitor);
}
複製程式碼

第二步:定義具體元素(具體某一個英雄)

首先我們可以定義甄姬

//甄姬
public class ZhenHero
extends Hero
{ //可以接受玩家的操作 @Override public void accept(Player visitor) { visitor.visitZhen(this); } //自身的技能 public void operate() { System.out.println("甄姬放出了技能"); } } 複製程式碼

還有一個莊周

//莊周
public class ZhuangHero extends Hero {
	//接受外部的訪問
	@Override
	public void accept(Player visitor) {
		visitor.visitZhuang(this);
	}
	//自身的技能
    public void operate() {
    	System.out.println("莊周放出了技能");
    }
}
複製程式碼

第三步:定義抽象訪問者(玩家)

//玩家可以訪問甄姬和莊周的技能
public interface Player {
    public abstract void visitZhuang(ZhuangHero element);
    public abstract void visitZhen(ZhenHero element);
}
複製程式碼

第四步:定義具體訪問者(玩家我和其他玩家)

首先是我自己操作

public class PlayerMe implements Player {
	@Override
	public void visitZhuang(ZhuangHero element) {
		System.out.println("玩家我訪問莊周,莊周開始使出技能");
		element.operate();
	}
	@Override
	public void visitZhen(ZhenHero element) {
		System.out.println("玩家我訪問甄姬,甄姬開始使出技能");
		element.operate();
	}
}
複製程式碼

然後是其他玩家操作

public class PlayerOthers implements Player {
	@Override
	public void visitZhuang(ZhuangHero element) {
		System.out.println("玩家其他人訪問莊周,莊周開始使出技能");
		element.operate();
	}
	@Override
	public void visitZhen(ZhenHero element) {
		System.out.println("玩家其他人訪問甄姬,甄姬開始使出技能");
		element.operate();
	}
}
複製程式碼

第五步:定義物件結構

public class ObjectStructure {
    //儲存所有需要被訪問的元素
    private List<Hero> heros = new ArrayList<Hero>();
    public void handleRequest(Player visitor) {
        //訪問所有元素
        for(Hero hero : heros) {
            hero.accept(visitor);
        }
    }
    public void addHero(Hero hero) {
    	heros.add(hero);
    }
}
複製程式碼

第六步:客戶端測試一下

public class Client {
	public static void main(String[] args) {
		ObjectStructure os = new ObjectStructure();
		Hero zhuang = new ZhuangHero();
		Hero zhen = new ZhenHero();

		os.addHero(zhuang);
		os.addHero(zhen);

		Player visitorMe = new PlayerMe();
		Player visitorOthers = new PlayerOthers();
		// 讓訪問者訪問物件結構中的元素
		os.handleRequest(visitorMe);
		os.handleRequest(visitorOthers);
	}
}
複製程式碼

最後一步我們就能看到結果了

這就是訪問者模式。

三、分析訪問者模式

訪問者模式使用的條件在於物件的結構一般不宜發生改變,但是操作缺不一樣的情況。比如複雜的集合物件、XML檔案解析、編譯器的設計等就常常會用到這個模式。

優點在於訪問者模式解決的問題,也就是使用場景,缺點就是不使用物件結構宜發生改變的情況。