1. 程式人生 > >Java進階篇設計模式之九----- 直譯器模式和迭代器模式

Java進階篇設計模式之九----- 直譯器模式和迭代器模式

前言

上一篇中我們學習了行為型模式的責任鏈模式(Chain of Responsibility Pattern)和命令模式(Command Pattern)。本篇則來學習下行為型模式的兩個模式, 直譯器模式(Interpreter Pattern)和迭代器模式(Iterator Pattern)。

直譯器模式

簡介

直譯器模式顧名思義,就是對某事物進行解釋。給定一個語言之後,直譯器模式可以定義出其文法的一種表示,並同時提供一個直譯器。客戶端可以使用這個直譯器來解釋這個語言中的句子。

直譯器模式其實就是對某事物進行解釋。比如生活中經常用到的計算器,將我們用的語言轉換成計算器預言,還有我們編寫程式碼時用到的正則表示式

等等。《大話設計模式》中對這個模式有個比較有意思的講解,其中示例就是把老闆對不同人說相同的話,不同的人會理解不同。這也說明的直譯器模式核心就是進行解釋。

直譯器模式主要由這四個角色組成,抽象表示式(Expression)角色、終結符表示式(Terminal Expression)角色、非終結符表示式(Nonterminal Expression)角色和環境(Context)角色。

  • 抽象直譯器:宣告一個所有具體表達式都要實現的抽象介面(或者抽象類),介面中主要是一個interpret()方法,稱為解釋操作。具體解釋任務由它的各個實現類來完成,具體的直譯器分別由終結符直譯器TerminalExpression和非終結符直譯器NonterminalExpression完成。
  • 終結符表示式:實現與文法中的元素相關聯的解釋操作,通常一個直譯器模式中只有一個終結符表示式,但有多個例項,對應不同的終結符。終結符一半是文法中的運算單元,比如有一個簡單的公式R=R1+R2,在裡面R1和R2就是終結符,對應的解析R1和R2的直譯器就是終結符表示式。
  • 非終結符表示式:文法中的每條規則對應於一個非終結符表示式,非終結符表示式一般是文法中的運算子或者其他關鍵字,比如公式R=R1+R2中,+就是非終結符,解析+的直譯器就是一個非終結符表示式。非終結符表示式根據邏輯的複雜程度而增加,原則上每個文法規則都對應一個非終結符表示式。
  • 環境角色:這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些資訊需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。

這裡為了方便理解,我們使用一個簡單的示例來加以說明。
平常我們在進行英語學習的時候,會自行翻譯或者用到翻譯工具。但是不同的翻譯工具翻譯的結果也可能不一樣,這時我們只需要拿到自己想要的結果就行了。比如,使用百度和有道翻譯“好好學習,天天向上!”,它們翻譯的結果分別為“Study hard and keep up!”和“study hard and make progress every day!”,而xuwujing翻譯的結果是“ Good good study, day day up!”。
那麼我們便可以用直譯器模式來實現這種場景。
首先定義一個抽象的直譯器介面,有解釋的這個方法,然後再定義不同的直譯器實現該介面和方法,最後再來進行測試。那麼程式碼如下:

interface Expreeion{
   void interpert(String word);
}

class  BaiduExpreeion implements Expreeion{
   String str ="好好學習,天天向上!";
   @Override
   public void interpert(String word) {
   	if(str.equals(word)) {
   		System.out.println("百度翻譯:"+word+" 的英文是  Study hard and keep up!");
   	}
   }
}

class  YouDaoExpreeion implements Expreeion{
   String str ="好好學習,天天向上!";
   @Override
   public void interpert(String word) {
   	if(str.equals(word)) {
   		System.out.println("有道翻譯:"+word+" 的英文是  study hard and make progress every day!");
   	}
   }
}

class  XuWuJingExpreeion implements Expreeion{
   String str ="好好學習,天天向上!";
   @Override
   public void interpert(String word) {
   	if(str.equals(word)) {
   		System.out.println("xuwujing翻譯:"+word+" 的英文是  Good good study, day day up!");
   	}
   }
}

public class InterpreterTest {
   public static void main(String[] args) {
   	String word = "好好學習,天天向上!";
   	Expreeion expreeion =new  BaiduExpreeion();
   	Expreeion expreeion2 =new  YouDaoExpreeion();
   	Expreeion expreeion3 =new  XuWuJingExpreeion();
   	expreeion.interpert(word);
   	expreeion2.interpert(word);
   	expreeion3.interpert(word);
   }
}

輸出結果:


百度翻譯:好好學習,天天向上! 的英文是  Study hard and keep up!
有道翻譯:好好學習,天天向上! 的英文是  study hard and make progress every day!
xuwujing翻譯:好好學習,天天向上! 的英文是  Good good study, day day up!

直譯器模式優點:

擴充套件性好,子類擴充套件非常方便。
實現簡單。

直譯器模式缺點:

可使用的場景比較少;
類過多的話,會使程式碼臃腫,難以維護;

使用場景:

一個簡單的語法規則需要解釋的場景,比如sql。
有重複的問題的時候。

迭代器模式

簡介

迭代器模式用於順序訪問集合物件的元素,不需要知道集合物件的底層表示,屬於行為型模式。 它提供一種方法順序訪問一個聚合物件中各個元素, 而又無須暴露該物件的內部表示。

我們對迭代器(Iterator)肯定不陌生,因為我們在Java開發中會經常用到,比如對List、Set和Map集合進行遍歷或對陣列進行遍歷的時候。但是迭代器模式的話,可能就不太理解了,這裡我們就簡單講講迭代器模式。

迭代器模式主要由這四個角色組成,迭代器角色(Iterator)、具體迭代器角色(Concrete Iterator)、容器角色(Container)和具體容器角色(Concrete Container)。

  • 迭代器角色(Iterator):通過介面或抽象類宣告實現的方法。
  • 具體迭代器角色(Concrete Iterator):具體迭代器角色要實現迭代器介面,並要記錄遍歷中的當前位置。
  • 容器角色(Container):容器角色負責提供建立具體迭代器角色的介面。
  • 具體容器角色(Concrete Container):具體容器角色實現建立具體迭代器角色的介面——這個具體迭代器角色於該容器的結構相關。

因為迭代器我們平時用的比較多,這裡也不在過多描述了,這裡就簡單的介紹下迭代器模式的運作。
首先,定義一個迭代器角色(MyIterator )和容器角色(MyIterable)的介面。
程式碼如下:

interface MyIterator {
	boolean hasNext();
	String next();
}

interface MyIterable{
	MyIterator getIterator();
	void add(String str);
	String get(int index);
}

然後定義一個 具體容器角色(ListContainer )實現容器角色的介面,這裡的實現方法通過List自帶的進行實現;然後再定義一個具體迭代器角色(ListIterator )實現迭代器角色的介面,這裡的實現的方法由自己實現。
那麼程式碼如下:


class ListContainer implements MyIterable {
	
	 private List<String> list =new ArrayList<>(); 

	 
	@Override
	public MyIterator getIterator() {
		return new ListIterator();
	}

	@Override
	public void add(String str) {
		list.add(str);
	}

	@Override
	public String get(int index) {
		return list.get(index);
	}
	
	class ListIterator implements MyIterator{
		int index;
		@Override
		public boolean hasNext() {
			return index < list.size();
		}

		@Override
		public String next() {
			if (this.hasNext()) {
				return list.get(index++);
			}
			return null;
		}
	}
}

最後再來進行程式碼的測試。
測試程式碼如下:


public static void main(String[] args) {
		MyIterable myIterable = new ListContainer();
		myIterable.add("1");
		myIterable.add("zhangsan");
		myIterable.add("2");
		myIterable.add("lisi");
		myIterable.add("3");
		myIterable.add("xuwujing");	
        MyIterator myIterator = myIterable.getIterator();
        while (myIterator.hasNext()){
            String str = myIterator.next();
            System.out.println(str);
        }      
	}

輸出結果:

		1
		zhangsan
		2
		lisi
		3
		xuwujing

迭代器模式優點:

靈活度高,可以通過不同的方式遍歷物件;
擴充套件性好,可以很方便的增加新的聚合類和迭代器類而不用修改之前的程式碼。

迭代器模式缺點:

由於迭代器模式將儲存資料和遍歷資料的職責分離,增加新的聚合類需要對應增加新的迭代器類,類的個數成對增加,這在一定程度上增加了系統的複雜性。

使用場景:

需要為聚合物件提供遍歷的功能的時候。

其它

音樂推薦

分享一首很好聽的日語歌曲!

專案的程式碼

java-study 是本人在學習Java過程中記錄的一些程式碼,也包括之前博文中使用的程式碼。如果感覺不錯,希望順手給個start,當然如果有不足,也希望提出。
github地址: https://github.com/xuwujing/java-study