在《淺談設計模式的學習(上)》中我說到了設計模式的基石-----抽象思惟。爲何須要抽象思惟呢?由於越抽象就越不容易出錯,就像有些領導人說話:堅持改革開放。但怎麼算堅持改革開放呢,沒有具體的標準,因事而異,因此就不容易違背這個堅持改革開放的原則了。java
三、學習設計模式,要保持抽象的思惟編程
什麼是抽象思惟呢?真的很差說,抽象的東西每每難以說明白,聽了也難以搞明白,仍是經過具體的例子來講吧
設計模式
有這麼一個學生請假的場景,若是請假時間一天之內則有班長批准就能夠了,三天之內則須要老師批准,超過三天就得找校長審批了,校長能審批不超過五天,超過五天就須要開會解決了。在這裏咱們就以這個場景爲例,展現一下如何抽象編程。ide
第一步:學習
在上邊的請假流程中咱們看到了班長、老師、校長等實體(爲了把注意力放在請假流程上,暫不對學生和請假實體多處理)。運用抽象思惟咱們抽象一下,這幾個實體有什麼共同特徵呢?對他們都是人,好吧咱們就寫一我的的接口,可是裏邊該有什麼方法呢?與咱們上邊需求相關的方法目前尚未,不要緊,暫時空着this
public interface IPerson { }
第二步:在第一步中絕對夠抽象了吧,咱們如今再具體一點吧,一步步往下具體。班長、老師、校長都是什麼人呢?是否是都有必定的管理權力啊,並且在咱們這個需求裏,他們都有批准假期的權力,同時班長、校長都有本身的上級領導。如今咱們的接口出來了:spa
public interface IManager extends IPerson{ public void process(Request request); public void setLeader(IManager leader); }
這裏用到了請求實體類:設計
public class Request { /**請假人名字*/ private String name; /**請假天數*/ private int days; /**請假緣由*/ private String cause; /**請假日期*/ private Date date; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getDays() { return days; } public void setDays(int days) { this.days = days; } public String getCause() { return cause; } public void setCause(String cause) { this.cause = cause; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
第三步:咱們再往下具體,在IManager接口中有兩個方法,設置領導的方法和處理請假請求的方法。試想一下,設置上級領導的方法對班長、老師和校長來講是否是都是同樣的。同時處理請假的流程也是同樣的,想一想看,每一個領導是否是都是先根據本身的批准能力來,若是請假天數在本身的批准能力範圍內則處理,超過了則請求本身的上級領導批准。而具體怎麼處理,每一個領導則是不一樣的對吧。因此這裏在一個抽象類裏實現了設置領導和批假的模板方法,並抽象了一個具體批准處理的抽象方法。來看代碼:blog
public abstract class AbstractManager implements IManager{ protected IManager leader; protected int handleDay; /** * * @param handleDay 能批准的天數 */ public AbstractManager(int handleDay){ this.handleDay = handleDay; } @Override public void setLeader(IManager leader) { this.leader=leader; } @Override public final void process(Request request) { boolean isOk = handleRequest(request); if(!isOk){ if(leader!=null){ leader.process(request); } } } /**假期處理方法*/ protected abstract boolean handleRequest(Request request); }
第四步:好了到這裏再往下具體就是咱們的實體:班長、老師、校長了。他們有各自的假期處理方式。下邊是班長、老師、校長三個實體類:接口
班長類:
public class Monitor extends AbstractManager { public Monitor(int handleDay) { super(handleDay); } @Override public boolean handleRequest(Request request) { if(this.handleDay>=request.getDays()){ System.out.println("班長:假期請求批准了"); return true; }else{ System.out.println("班長:沒有權限,請老師批准"); return false; } } }
老師類:
public class Teacher extends AbstractManager { public Teacher(int handleDay) { super(handleDay); } @Override protected boolean handleRequest(Request request) { if(this.handleDay>=request.getDays()){ System.out.println("老師:假期請求批准了"); return true; }else{ System.out.println("老師:沒有權限,讓校長批准"); return false; } } }
校長類:
public class SchoolMaster extends AbstractManager { public SchoolMaster(int handleDay) { super(handleDay); } @Override protected boolean handleRequest(Request request) { if(this.handleDay>=request.getDays()){ System.out.println("校長:假期請求批准了"); return true; }else{ System.out.println("校長:沒有權限,咱們開會商量一下"); return false; } } }
第五步:咱們以Client爲學生作假期的請求申請,看看Client的代碼:
public class Client { public static void main(String[] args) { Request request = new Request(); request.setName("小李"); request.setDays(6); request.setDate(new Date()); request.setCause("不舒服"); IManager monitor = new Monitor(1); IManager teacher = new Teacher(3); IManager master = new SchoolMaster(5); monitor.setLeader(teacher); teacher.setLeader(master); monitor.process(request); } }
到這裏整個流程結束了。這就是咱們從抽象一步步走向具體的過程。聰明的你可能已經看出代碼使用的什麼設計模式。就是責任鏈模式。但這裏有你更應該注意的一個設計模式-------模板方法模式。
在AbstractManager的process方法中咱們用了final修飾,就是不讓子類重寫此方法,由於客戶端就是調用此方法來完成處理流程的,這是一個模板方法,在模板方法裏咱們調用了抽象方法handleRequest()。而handleRequest則是根據具體的領導具體實現。
模板方法能夠說是無處不在,好比servlet的service方法,若是你讀一些開源項目,會發現更多的模板方法,因此掌握此模式絕對是有必要的。而模板方法模式就是將相同的處理流程提取到了抽象類中,具體處理方式則由子類來實現。因此一切還要從抽象開始。