三、行為型模式
行為型模式是使用較為頻繁也是相對有些理解難度的模式。主要針對不同的業(yè)務(wù)需求對對象的行為進(jìn)行優(yōu)化和改進(jìn),使之更加合理,讓業(yè)務(wù)更加流暢穩(wěn)定,同時也更便于代碼閱讀理解。
行為型模式主要包括觀察者模式、責(zé)任鏈模式、命令模式、迭代器模式、中介者模式、備忘錄模式、狀態(tài)模式、策略模式、訪問者模式。以下詳細(xì)介紹。
觀察者模式
這種模式主要用于監(jiān)聽對象的行為或狀態(tài)變化,當(dāng)被觀察對象的狀態(tài)發(fā)生改變時,迅速通知到觀察者,因此通常是一對多的關(guān)系,即一個被觀察者多個觀察者。比如警察常常要接聽報警電話,觀察者就是警察,觀察對象就是每一個報警求助的人,觀察途徑就是電話。另外求助者可能向警察求助,也有可能想親朋好友求助,所以可能會有多個觀察者。如下圖:

報警電話為一個接口,警察和求助者都持有,這是他們互通信息的一個通道。
public interface DangerListener {
void somethingHappen(String event);
}
求助者擁有一個電話本,只要有人告訴他號碼他就會存下來,和他斷交就會刪掉這個號碼,因此他有一個電話集合。當(dāng)他遇到危險,就會把這個信息向電話集合中的人群發(fā)擴(kuò)散以獲得幫助。
public class HelperSeeker {
private List<DangerListener> listeners = new ArrayList<>();
private static HelperSeeker seeker;
public static HelperSeeker getInstance(){
if (seeker == null){
seeker = new HelperSeeker();
}
return seeker;
}
public void registerDanger(DangerListener listener){
listeners.add(listener);
}
public void unRegisterDanger(DangerListener listener){
listeners.remove(listener);
}
public void help(){
for (DangerListener listener:listeners){
listener.somethingHappen("help");
}
}
}
警察擁有這個求助者的信息,并告訴他自己的聯(lián)系方式,當(dāng)收到他的求助信息時就會采取保護(hù)行動。當(dāng)警察換崗位或者離職或是退休之后就會告訴該求助者不用保存自己的號碼了。
public class ObserverPolice {
private DangerListener listener = new DangerListener() {
@Override
public void somethingHappen(String event) {
System.out.println("ObserverPolice receive msg for "+event);
}
};
public void action(){
HelperSeeker seeker = HelperSeeker.getInstance();
seeker.registerDanger(listener);
}
public void onChange(){
HelperSeeker.getInstance().unRegisterDanger(listener);
}
}
責(zé)任鏈模式
責(zé)任鏈模式即接受者在處理請求的時候創(chuàng)建了一個對象鏈來進(jìn)行事件處理,這個對象鏈中每個接受者都擁有下一個的引用,當(dāng)自己能處理該請求時則自己處理掉,不能處理的話往下傳遞,直至處理完畢。類似“擊鼓傳花”。
例如,當(dāng)前要實現(xiàn)一個打印日志的功能,日志分三個級別,一般日志,錯誤日志和文件日志。等級越高的日志越是要謹(jǐn)慎打印,等級低的限制寬松一些,一般的都要打印。
還舉個例子,屏幕上有一個彈窗,彈窗上會進(jìn)行一些操作也會彈窗,彈窗上又有可能彈窗,簡而言之有多重彈窗,假如現(xiàn)在有三層彈窗,在最底層的頁面突然收到一個消息,要求把所有彈窗都消失掉。這時應(yīng)該怎么處理呢?
由于最底層的頁面是不應(yīng)該全部持有這三個彈窗的引用的,否則就會造成管理混亂,所以在收到通知的時候只需要在onDimiss()方法中將上面的一個彈窗取消掉就行,而上一個彈窗在取消的時候只需要判斷它上面有沒有彈窗,有的話就取消就行了,如此類推。當(dāng)一個彈窗取消的時候,它上面的所有彈窗都會取消掉。每一個彈窗都持有下一個彈窗的引用,都只負(fù)責(zé)自己是否取消。

代碼如下:
基類logger
public abstract class Logger {
public static final int LEVEL_CONSOLE = 0;
public static final int LEVEL_ERROR = 1;
public static final int LEVEL_FILE = 2;
private Logger nextLogger = getNextLogger();
protected abstract Logger getNextLogger();
private int curLevel = getLevel();
protected abstract int getLevel();
protected void loggerMsg(int level,String msg){
if (curLevel <= level){
logger(msg);
if (nextLogger != null){
nextLogger.logger(msg);
}
}
}
protected abstract void logger(String msg);
}
三個子類ConsoleLogger,ErrorLogger和FileLogger
public class ConsoleLogger extends Logger {
@Override
protected Logger getNextLogger() {
return new ErrorLogger();
}
@Override
protected int getLevel() {
return Logger.LEVEL_CONSOLE;
}
@Override
protected void logger(String msg) {
System.out.println("ConsoleLogger " + msg);
}
}
public class ErrorLogger extends Logger{
@Override
protected Logger getNextLogger() {
return new FileLogger();
}
@Override
protected int getLevel() {
return Logger.LEVEL_ERROR;
}
@Override
protected void logger(String msg) {
System.out.println("ErrorLogger "+msg);
}
}
public class FileLogger extends Logger{
@Override
protected Logger getNextLogger() {
return null;
}
@Override
protected int getLevel() {
return Logger.LEVEL_FILE;
}
@Override
protected void logger(String msg) {
System.out.println("FileLogger "+msg);
}
}
測試
public class Test {
public static void main(String[] args) {
ConsoleLogger logger = new ConsoleLogger();
logger.loggerMsg(Logger.LEVEL_ERROR,"error msg");
}
}
打印結(jié)果
ConsoleLogger error msg
ErrorLogger error msg
命令模式
命令模式就是將命令者和命令本身以及命令對象分別進(jìn)行封裝,這樣再多的命令都可以簡化。達(dá)到了對象之間的解耦。
將命令者和命令都抽象成接口,命令者持有命令引用而不關(guān)心命令如何去實現(xiàn)。一個典型的例子就是Android當(dāng)中的各個view。每個view都擁有自己的一套繪制流程,onMeasure(),onLayout(),onDraw(),等,view作為一個基類抽象了這些方法,而同時每個view又都是可以被點擊的,即view的觸摸事件分發(fā),這一套也抽象成了接口方法?;惓钟羞@一引用,具體的實現(xiàn)則由各自去實現(xiàn)。例如onClick(),onLongClick(),onDrag()等。如下圖:

View
public abstract class View {
protected TouchEvent touchEvent;
protected String name;
public View(String name,TouchEvent touchEvent) {
this.name = name;
this.touchEvent = touchEvent;
}
public void touch(){
touchEvent.onTouch();
}
public String getName(){
return name;
}
}
TextView
public class TextView extends View{
public TextView(String name, TouchEvent touchEvent) {
super(name, touchEvent);
}
}
TouchEvent
public interface TouchEvent {
void onTouch();
}
DragEvent
public class DragEvent implements TouchEvent{
@Override
public void onTouch() {
System.out.println("DragEvent ...");
}
}
ClickEvent
public class ClickEvent implements TouchEvent{
@Override
public void onTouch() {
System.out.println("ClickEvent ...");
}
}
測試代碼:
public static void main(String[] args) {
ClickEvent clickEvent = new ClickEvent();
DragEvent dragEvent = new DragEvent();
TextView textView1 = new TextView("textView1",clickEvent);
System.out.print(textView1.getName()+" ");
textView1.touch();
TextView textView2 = new TextView("textView2",dragEvent);
System.out.print(textView2.getName()+" ");
textView2.touch();
}
迭代器模式
這種模式用于順序訪問集合對象的元素,不需要知道集合對象的底層表示。一般用于集合中,例如iterator接口,它的實現(xiàn)類有很多種如ArrayList(),LinkList()等等,具體可以直接看jdk源碼。