1. 程式人生 > >java設計模式學習筆記(三) --- 行為型模式

java設計模式學習筆記(三) --- 行為型模式

文章目錄

責任鏈模式

我獲取了一個物件,現在需要根據物件內部的特徵來把它交給特定的類去處理。下面是一種簡單的實現方法。

package blog.java.pattern.chain;

public class ChainTest {

	public static void main(String[] args) {
		Obj obj = new
Obj((int)(Math.random() * 2)); IInterface impl; if(obj.flag == 0){//根據flag的值來確定具體由哪個實現類來處理。 impl = new Impl_1(); }else { impl = new Impl_2(); } impl.doSomething(obj); } } class Obj{ int flag; public Obj(int flag) { this.flag = flag; } } interface IInterface{public void
doSomething(Obj obj);} class Impl_1 implements IInterface{ public void doSomething(Obj obj) { System.out.println(1 + " " + obj); } } class Impl_2 implements IInterface{ public void doSomething(Obj obj) { System.out.println(2 + " " + obj); } }

這麼寫可以解決問題,但是有缺陷。

作為客戶端,我不想判斷到底是誰去處理,這應該在別的地方判斷。
在實際問題中,判斷可能遠不止obj.flag == 0

這樣簡單,如果把一大坨判斷都放一起,維護會很麻煩。

責任鏈模式為這種問題提供了一種解決方法:讓處理類通過持有物件的方式,鏈式的判斷是否由自己處理。

package blog.java.pattern.chain;

public class ChainTest {

	public static void main(String[] args) {
		Obj obj = new Obj((int)(Math.random() * 2));
		
		IInterface impl1 = new Impl_1();
		IInterface impl2 = new Impl_2();
		impl1.setNextImpl(impl2);
		
		impl1.doSomething(obj);
	}

}

class Obj{
	int flag;
	public Obj(int flag) {
		this.flag = flag;
	}
}

interface IInterface{
	public void doSomething(Obj obj);
	public void setNextImpl(IInterface nextImpl);
}

abstract class BaseImpl implements IInterface{
	IInterface nextImpl;

	public void setNextImpl(IInterface nextImpl) {
		this.nextImpl = nextImpl;
	}
}

class Impl_1 extends BaseImpl implements IInterface{
	public void doSomething(Obj obj) { 
		if(obj.flag == 0)
			System.out.println(1 + " " + obj);
		else 
			super.nextImpl.doSomething(obj);
	}
}

class Impl_2 extends BaseImpl implements IInterface{
	public void doSomething(Obj obj) { 
		if(obj.flag == 1)
			System.out.println(2 + " " + obj); 
		else 
			super.nextImpl.doSomething(obj);
	}
}

策略模式

將用介面組織的一套方法,通過另一個類間接呼叫。

package blog.java.pattern.strategy;

public class StrategyTest {

	public static void main(String[] args) {
		Invoker invoker = new Invoker(new Strategy_1());
		invoker.execute();
		invoker = new Invoker(new Strategy_2());
		invoker.execute();
	}
}

interface IStrategy{public void doSomething();}

class Strategy_1 implements IStrategy{public void doSomething(){System.out.println("Strategy_1");}}
class Strategy_2 implements IStrategy{public void doSomething(){System.out.println("Strategy_2");}}
class Strategy_3 implements IStrategy{public void doSomething(){System.out.println("Strategy_3");}}

class Invoker{
	IStrategy strategy;
	public Invoker(IStrategy strategy) {
		this.strategy = strategy;
	}
	public void execute(){
		this.strategy.doSomething();
	}
}

很樸實的解耦,完全不需要解釋。

命令模式

我需要執行一些複雜的功能,它們可能需要一個或多個類進行一系列操作才能完成。於是我把它們封裝到了另一個類B中來執行。同時,我又不想直接操作類B,而是通過另一個類來間接執行。

package blog.java.pattern.command;

public class CommandTest {
	public static void main(String[] args) {
		Invoker invoker = new Invoker();
		invoker.setCommand(new ACommand());
		invoker.execute();
	}
}

class Receiver{	//執行具體操作
	public void doA(){}
	public void doB(){}
	public void doC(){}
}

interface ICommand{public void execute();}

abstract class CommandFather implements ICommand{
	Receiver receiver = new Receiver();
}

class ACommand extends CommandFather{//A命令
	public void execute() {
		this.receiver.doA();
	} 
}

class BCommand extends CommandFather{//B命令
	public void execute() {
		this.receiver.doB();
		this.receiver.doC();
	} 
}

class Invoker{//客戶端直接呼叫的物件,主要為了將客戶端與命令類分開
	private ICommand command;

	public void setCommand(ICommand command) {
		this.command = command;
	}
	
	public void execute(){
		this.command.execute();
	}
}

直譯器模式

簡單來說,就用面向物件的方式去解析語言。

應用面很窄,替代品很多,又解決不了真正複雜的問題…
用得到的時候再看吧。

迭代器模式

迭代器模式規定,一個集合類,需要在不暴露內部儲存結構的前提下,提供一個順序遍歷自身資料的方法。

這個模式幾乎不會在我們的程式碼中出現,不是因為沒用,而是太有用了。java所有的集合類都已經實現了這個方法,不需要我們去寫了。

個人覺得,學這個設計模式的最好方法就是直接看jdk原始碼,那裡有優秀的,經過實踐檢驗的示例。

這是我之前寫的ArrayList的迭代器模式的實現。ArrayList的底層是靜態陣列,它的迭代器是最簡單的,可以作為參考。
通過ArrayList原始碼深入理解java中Iterator迭代器的實現原理

中介者模式

若一組類之間存在多對多的關係(即每個類若想要實現某個方法,可能會呼叫多個其他類),則它們之間互稱為同事類。在同事類中存在這種關係的方法中,會有很多呼叫其它同事類的程式碼。將同事類中這些相互呼叫的程式碼封裝起來,就是中介者模式。
實現方法簡單描述一下就是:中介者類持有全部的同事類物件;同事類持有一箇中介者物件,並通過中介者物件來間接實現方法。

package blog.java.pattern.mediator;

public class MediatorTest {

	public static void main(String[] args) {
		Colleague_1 c1 = new Colleague_1();
		Colleague_2 c2 = new Colleague_2();
		Colleague_3 c3 = new Colleague_3();
		
		Mediator mediator = new Mediator();
		mediator.setC1(c1);
		mediator.setC2(c2);
		mediator.setC3(c3);
		
		IMediator iMediator = mediator;
		
		c1.setiMediator(iMediator);
		c2.setiMediator(iMediator);
		c3.setiMediator(iMediator);
		
		c1.Colleague_1_method1();	//呼叫
		c2.Colleague_2_method1();	//呼叫
	}

}

interface IMediator{
	public void method1();
	public void method2();
}

abstract class AbstractMediator implements IMediator{
	protected Colleague_1 c1;
	protected Colleague_2 c2;
	protected Colleague_3 c3;
	public void setC1(Colleague_1 c1) {
		this.c1 = c1;
	}
	public void setC2(Colleague_2 c2) {
		this.c2 = c2;
	}
	public void setC3(Colleague_3 c3) {
		this.c3 = c3;
	}
}
//中介者
class Mediator extends AbstractMediator{
	@Override
	public void method1() {
		super.c1.Colleague_1_method2();
		super.c2.Colleague_2_method1();
	}
	@Override
	public void method2() {
		super.c3.Colleague_3_method1();
		super.c1.Colleague_1_method3();
	}
}
//同事類
class Colleague_1{
	private IMediator iMediator;
	public void setiMediator(IMediator iMediator) {
		this.iMediator = iMediator;
	}
	
	public void Colleague_1_method1(){
		this.iMediator.method1();
	}
	public void Colleague_1_method2(){}
	public void Colleague_1_method3(){}
}

class Colleague_2{
	private IMediator iMediator;
	public void setiMediator(IMediator iMediator) {
		this.iMediator = iMediator;
	}
	
	public void Colleague_2_method1(){
		this.iMediator.method2();
	}
}

class Colleague_3{
	private IMediator iMediator;
	public void setiMediator(IMediator iMediator) {
		this.iMediator = iMediator;
	}
	
	public void Colleague_3_method1(){}
}

垃圾程式碼的形成往往是,錯誤的人,通過錯誤的方法,使用了錯誤的設計模式。中介者模式很可能三者全佔。
中介者模式的一大特點是,將原本同事類中複雜的程式碼,以更復雜的方式寫在了中介者類中。中介者類設計的失敗很可能會成為專案中的毒瘤。而且,若同事類中的邏輯本就不復雜,也是不太需要使用設計模式的。

不過若是使用得合適的話,確實可以使類的結構更清晰。它會使每一個同事類只與中介者類產生耦合關係。

中介者模式的一個核心思想是,將類間的控制提取出來,單獨封裝。這種思想或許比那些模板式的實現方法更有價值,MVC中的C正式用的這種思想。

備忘錄模式

簡單來說,就是存檔/讀檔。將當前類的部分內容存檔,並在需要的時候將類恢復到原來的狀態。
具體的實現方法會根據需求的不同而有較大的變化。簡單描述的一下的話,就是除了原本的需要備份的類外,還需要一個用於存檔的類與一個管理存檔的類。簡單實現一下。

package blog.java.pattern.memento;

public class MementoTest {

	public static void main(String[] args) {
		Originator originator = new Originator();
		originator.setProp1("1");
		System.out.println(originator.getProp1());
		originator.createMemento();		//存檔
		originator.setProp1("2");
		System.out.println(originator.getProp1());
		originator.restoreMemento();	//讀檔
		System.out.println(originator.getProp1());
	}

}

class Originator{
	private String prop1;
	
	private Caretaker caretaker = new Caretaker();
	
	public void createMemento(){
		Memento memento = new Memento();
		memento.setProp1(this.prop1);
		this.caretaker.setMemento(memento);
	}
	
	public void restoreMemento(){
		Memento memento = this.caretaker.getMemento();
		this.prop1 = memento.getProp1();
	}

	public String getProp1() {
		return prop1;
	}

	public void setProp1(String prop1) {
		this.prop1 = prop1;
	}

	private class Memento{
		private String prop1;

		public String getProp1() {
			return prop1;
		}

		public void setProp1(String prop1) {
			this.prop1 = prop1;
		}
		
	}
	
	private class Caretaker{
		private Memento memento;
		public void setMemento(Memento memento){
			this.memento = memento;
		}
		public Memento getMemento() {
			return memento;
		}
	}
	
}

與其他大多數示例不同的是,我將管理者類也寫成內部類了。這可能有些不符合單一職責原則,但是我更喜歡用可自我維護的類。這樣在呼叫的時候,我只需要關注這一個類。

對於更復雜的情況,比如需要備份的內容更多,更復雜,或者需要多個備份,只要按這個模板稍稍改下就行了。

觀察者模式

(被觀察者)執行某些操作後,想要立即呼叫其他一組類(觀察者)的方法。這時考慮使用觀察者模式。(總覺得設計模式從我嘴裡說出來後,都low了好多…)

按照這句話的需求,很容易就能寫出這樣的程式碼。

package blog.java.pattern.observer;

import java.util.ArrayList;
import java.util.List;

public class ObserverTest {

	public static void main(String[] args) {
		MyObservable observable = new MyObservable();
		observable.method();
	}

}

//被觀察者
class MyObservable{
	List<IMyObserver> list = new ArrayList<IMyObserver>();
	{
		list.add(new MyObserver1());
		list.add(new MyObserver2());
	}
	
	public void method(){
		this.notifyOb();
	}
	
	private void notifyOb(){
		for(IMyObserver iMyObserver: list){
			iMyObserver.update(this);
		}
	}
}

interface IMyObserver{
	public void update(Object obj);
}
//觀察者
class MyObserver1 implements IMyObserver{
	public void update(Object obj) {
		System.out.println("1 " + obj);
	}
}

class MyObserver2 implements IMyObserver{
	public void update(Object obj) {
		System.out.println("2 " + obj);
	}
}

這個應該算是觀察者模式最簡陋的實現了。想寫的正規些的話,可以直接使用util包中準備好的類。jdk從1.0版本就已經提供觀察者介面與被觀察者類了。

		java.util.Observable
		java.util.Observer

原始碼非常簡單,按照上面的套路,稍稍改下就能用。
主要的改變是:增加了被觀察者中對觀察者的維護方法;被觀察者狀態變化的維護;一些必要的同步。

參考程式碼

package blog.java.pattern.observer.better;

import java.util.Observable;
import java.util.Observer;

public class ObserverTest2 {
	public static void main(String[] args) {
		MyObservable observable = new MyObservable();
		observable.addObserver(new MyObserver2