1. 程式人生 > >Java設計模式簡介(三):行為型模式(上)

Java設計模式簡介(三):行為型模式(上)

本章講到第三種設計模式——行為型模式,共11種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。

先來張圖,看看這11中模式的關係:

第一類:通過父類與子類的關係進行實現。第二類:兩個類之間。第三類:類的狀態。第四類:通過中間類。

 

13、策略模式(strategy):

策略模式定義了一系列的演算法,並將每個演算法封裝起來,使他們可以相互替換,且演算法的變換不會影響到使用演算法的客戶。需要設計一個介面,為一系列實現類提供統一的方法,多個實現類實現該介面,設計一個抽象類(可有可無),提供輔助類,提供輔助函式,關係圖如下:

圖中ICalculator提供統一的方法,
AbstractCalculator是輔助類,提供輔助方法,接下來,依次實現下每個類:

首先統一介面:

public interface ICalculator {
	public int calculate(String exp);
}

輔助類:

public abstract class AbstractCalculator {
	
	public int[] split(String exp,String opt){
		String array[] = exp.split(opt);
		int arrayInt[] = new int[2];
		arrayInt[0] = Integer.parseInt(array[0]);
		arrayInt[1] = Integer.parseInt(array[1]);
		return arrayInt;
	}
}

三個實現類:

public class Plus extends AbstractCalculator implements ICalculator {
 
	@Override
	public int calculate(String exp) {
		int arrayInt[] = split(exp,"\\+");
		return arrayInt[0]+arrayInt[1];
	}
}
public class Minus extends AbstractCalculator implements ICalculator {
 
	@Override
	public int calculate(String exp) {
		int arrayInt[] = split(exp,"-");
		return arrayInt[0]-arrayInt[1];
	}
 
}
public class Multiply extends AbstractCalculator implements ICalculator {
 
	@Override
	public int calculate(String exp) {
		int arrayInt[] = split(exp,"\\*");
		return arrayInt[0]*arrayInt[1];
	}
}

簡單的測試類:

public class StrategyTest {
 
	public static void main(String[] args) {
		String exp = "2+8";
		ICalculator cal = new Plus();
		int result = cal.calculate(exp);
		System.out.println(result);
	}
}

輸出:10

策略模式的決定權在使用者,系統本身提供不同演算法的實現,新增或者刪除演算法,對各種演算法做封裝。因此,策略模式多用在演算法決策系統中,外部使用者只需要決定用哪個演算法即可。

 

14、模板方法模式(Template Method):

解釋一下模板方法模式,就是指:一個抽象類中,有一個主方法,再定義1...n個方法,可以是抽象的,也可以是實際的方法,定義一個類,繼承該抽象類,重寫抽象方法,通過呼叫抽象類,實現對子類的呼叫,先看個關係圖:

就是在AbstractCalculator類中定義一個主方法calculate,calculate()呼叫spilt()等,Plus和Minus分別繼承AbstractCalculator類,通過對AbstractCalculator的呼叫實現對子類的呼叫,看下面的例子:

public abstract class AbstractCalculator {
	
	/*主方法,實現對本類其它方法的呼叫*/
	public final int calculate(String exp,String opt){
		int array[] = split(exp,opt);
		return calculate(array[0],array[1]);
	}
	
	/*被子類重寫的方法*/
	abstract public int calculate(int num1,int num2);
	
	public int[] split(String exp,String opt){
		String array[] = exp.split(opt);
		int arrayInt[] = new int[2];
		arrayInt[0] = Integer.parseInt(array[0]);
		arrayInt[1] = Integer.parseInt(array[1]);
		return arrayInt;
	}
}
public class Plus extends AbstractCalculator {
 
	@Override
	public int calculate(int num1,int num2) {
		return num1 + num2;
	}
}
public class StrategyTest {
 
	public static void main(String[] args) {
		String exp = "8+8";
		AbstractCalculator cal = new Plus();
		int result = cal.calculate(exp, "\\+");
		System.out.println(result);
	}
}

測試類:

public class StrategyTest {
 
	public static void main(String[] args) {
		String exp = "8+8";
		AbstractCalculator cal = new Plus();
		int result = cal.calculate(exp, "\\+");
		System.out.println(result);
	}
}

我跟蹤下這個小程式的執行過程:首先將exp和"\\+"做引數,呼叫AbstractCalculator類裡的calculate(String,String)方法,在calculate(String,String)裡呼叫同類的split(),之後再呼叫calculate(int ,int)方法,從這個方法進入到子類中,執行完return num1 + num2後,將值返回到AbstractCalculator類,賦給result,打印出來。正好驗證了我們開頭的思路。
 

15、觀察者模式(Observer):

包括這個模式在內的接下來的四個模式,都是類和類之間的關係,不涉及到繼承,學的時候應該 記得歸納,記得本文最開始的那個圖。觀察者模式很好理解,類似於郵件訂閱和RSS訂閱,當我們瀏覽一些部落格或wiki時,經常會看到RSS圖示,就這的意思是,當你訂閱了該文章,如果後續有更新,會及時通知你。其實,簡單來講就一句話:當一個物件變化時,其它依賴該物件的物件都會收到通知,並且隨著變化!物件之間是一種一對多的關係。先來看看關係圖:

我解釋下這些類的作用:MySubject類就是我們的主物件,Observer1和Observer2是依賴於MySubject的物件,當MySubject變化時,Observer1和Observer2必然變化。AbstractSubject類中定義著需要監控的物件列表,可以對其進行修改:增加或刪除被監控物件,且當MySubject變化時,負責通知在列表記憶體在的物件。我們看實現程式碼:

一個Observer介面:

public interface Observer {
	public void update();
}

兩個實現類:

public class Observer1 implements Observer {
 
	@Override
	public void update() {
		System.out.println("observer1 has received!");
	}
}
public class Observer2 implements Observer {
 
	@Override
	public void update() {
		System.out.println("observer2 has received!");
	}
 
}

Subject介面及實現類:

public interface Subject {
	
	/*增加觀察者*/
	public void add(Observer observer);
	
	/*刪除觀察者*/
	public void del(Observer observer);
	
	/*通知所有的觀察者*/
	public void notifyObservers();
	
	/*自身的操作*/
	public void operation();
}
public abstract class AbstractSubject implements Subject {
 
	private Vector<Observer> vector = new Vector<Observer>();
	@Override
	public void add(Observer observer) {
		vector.add(observer);
	}
 
	@Override
	public void del(Observer observer) {
		vector.remove(observer);
	}
 
	@Override
	public void notifyObservers() {
		Enumeration<Observer> enumo = vector.elements();
		while(enumo.hasMoreElements()){
			enumo.nextElement().update();
		}
	}
}
public class MySubject extends AbstractSubject {
 
	@Override
	public void operation() {
		System.out.println("update self!");
		notifyObservers();
	}
 
}

測試類:

public class ObserverTest {
 
	public static void main(String[] args) {
		Subject sub = new MySubject();
		sub.add(new Observer1());
		sub.add(new Observer2());
		
		sub.operation();
	}
 
}

執行結果:

update self!
observer1 has received!
observer2 has received!

 這些東西,其實不難,只是有些抽象,不太容易整體理解,建議讀者:根據關係圖,新建專案,自己寫程式碼(或者參考我的程式碼),按照總體思路走一遍,這樣才能體會它的思想,理解起來容易!

 

16、迭代子模式(Iterator):

顧名思義,迭代器模式就是順序訪問聚集中的物件,一般來說,集合中非常常見,如果對集合類比較熟悉的話,理解本模式會十分輕鬆。這句話包含兩層意思:一是需要遍歷的物件,即聚集物件,二是迭代器物件,用於對聚集物件進行遍歷訪問。我們看下關係圖:

這個思路和我們常用的一模一樣,MyCollection中定義了集合的一些操作,MyIterator中定義了一系列迭代操作,且持有Collection例項,我們來看看實現程式碼:

兩個介面:

public interface Collection {
	
	public Iterator iterator();
	
	/*取得集合元素*/
	public Object get(int i);
	
	/*取得集合大小*/
	public int size();
}
public interface Iterator {
	//前移
	public Object previous();
	
	//後移
	public Object next();
	public boolean hasNext();
	
	//取得第一個元素
	public Object first();
}

兩個實現:

public class MyCollection implements Collection {
 
	public String string[] = {"A","B","C","D","E"};
	@Override
	public Iterator iterator() {
		return new MyIterator(this);
	}
 
	@Override
	public Object get(int i) {
		return string[i];
	}
 
	@Override
	public int size() {
		return string.length;
	}
}
public class MyIterator implements Iterator {
 
	private Collection collection;
	private int pos = -1;
	
	public MyIterator(Collection collection){
		this.collection = collection;
	}
	
	@Override
	public Object previous() {
		if(pos > 0){
			pos--;
		}
		return collection.get(pos);
	}
 
	@Override
	public Object next() {
		if(pos<collection.size()-1){
			pos++;
		}
		return collection.get(pos);
	}
 
	@Override
	public boolean hasNext() {
		if(pos<collection.size()-1){
			return true;
		}else{
			return false;
		}
	}
 
	@Override
	public Object first() {
		pos = 0;
		return collection.get(pos);
	}
 
}

測試類:

public class Test {
 
	public static void main(String[] args) {
		Collection collection = new MyCollection();
		Iterator it = collection.iterator();
		
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}

輸出:A B C D E

此處我們貌似模擬了一個集合類的過程,感覺是不是很爽?其實JDK中各個類也都是這些基本的東西,加一些設計模式,再加一些優化放到一起的,只要我們把這些東西學會了,掌握好了,我們也可以寫出自己的集合類,甚至框架!

 

17、責任鏈模式(Chain of Responsibility):

責任鏈模式,有多個物件,每個物件持有對下一個物件的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一物件決定處理該請求。但是發出者並不清楚到底最終那個物件會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。先看看關係圖:

Abstracthandler類提供了get和set方法,方便MyHandle類設定和修改引用物件,MyHandle類是核心,例項化後生成一系列相互持有的物件,構成一條鏈。

public interface Handler {
	public void operator();
}
public abstract class AbstractHandler {
	
	private Handler handler;
 
	public Handler getHandler() {
		return handler;
	}
 
	public void setHandler(Handler handler) {
		this.handler = handler;
	}
	
}
public class MyHandler extends AbstractHandler implements Handler {
 
	private String name;
 
	public MyHandler(String name) {
		this.name = name;
	}
 
	@Override
	public void operator() {
		System.out.println(name+"deal!");
		if(getHandler()!=null){
			getHandler().operator();
		}
	}
}
public class Test {
 
	public static void main(String[] args) {
		MyHandler h1 = new MyHandler("h1");
		MyHandler h2 = new MyHandler("h2");
		MyHandler h3 = new MyHandler("h3");
 
		h1.setHandler(h2);
		h2.setHandler(h3);
 
		h1.operator();
	}
}

執行結果:

h1deal!
h2deal!
h3deal!

此處強調一點就是,連結上的請求可以是一條鏈,可以是一個樹,還可以是一個環,模式本身不約束這個,需要我們自己去實現,同時,在一個時刻,命令只允許由一個物件傳給另一個物件,而不允許傳給多個物件。

 

18、命令模式(Command):

命令模式很好理解,舉個例子,司令員下令讓士兵去幹件事情,從整個事情的角度來考慮,司令員的作用是,發出口令,口令經過傳遞,傳到了士兵耳朵裡,士兵去執行。這個過程好在,三者相互解耦,任何一方都不用去依賴其他人,只需要做好自己的事兒就行,司令員要的是結果,不會去關注到底士兵是怎麼實現的。我們看看關係圖:

Invoker是呼叫者(司令員),Receiver是被呼叫者(士兵),MyCommand是命令,實現了Command介面,持有接收物件,看實現程式碼:

public interface Command {
	public void exe();
}
public class MyCommand implements Command {
 
	private Receiver receiver;
	
	public MyCommand(Receiver receiver) {
		this.receiver = receiver;
	}
 
	@Override
	public void exe() {
		receiver.action();
	}
}
public class Receiver {
	public void action(){
		System.out.println("command received!");
	}
}
public class Invoker {
	
	private Command command;
	
	public Invoker(Command command) {
		this.command = command;
	}
 
	public void action(){
		command.exe();
	}
}
public class Test {
 
	public static void main(String[] args) {
		Receiver receiver = new Receiver();
		Command cmd = new MyCommand(receiver);
		Invoker invoker = new Invoker(cmd);
		invoker.action();
	}
}

執行結果:

command received!

這個很好理解,命令模式的目的就是達到命令的發出者和執行者之間解耦,實現請求和執行分開,熟悉Struts的同學應該知道,Struts其實就是一種將請求和呈現分離的技術,其中必然涉及命令模式的思想!

本篇暫時就到這裡,因為考慮到將來博文會不斷的更新,不斷的增加新內容,所以當前篇幅不易過長,以便大家閱讀,所以接下來的放到另一篇裡。
 

 

原文轉自:https://blog.csdn.net/zhangerqing/article/details/8243942