最易懂設(shè)計模式解析
適配器設(shè)計模式
Mybatis代理設(shè)計模式
Mybatis多級代理
1. 認識模板方法模式
1.1 模式定義
定義一個操作算法中的框架铺根,而將這些步驟延遲加載到子類中。
它的本質(zhì)就是固定算法框架乔宿。
1.2 解決何種問題
讓父類控制子類方法的調(diào)用順序
模板方法模式使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟位迂。
1.3 模式好處
開發(fā)人員在開發(fā)時,只需要考慮方法的實現(xiàn)详瑞。不需要考慮方法在何種情況下被調(diào)用掂林。實現(xiàn)代碼復(fù)用。
1.4 模式適合場景
- 一次性實現(xiàn)一個算法的不變部分坝橡,并將可變的行為留給子類來實現(xiàn)泻帮。
- 各子類中公共的行為應(yīng)被提取出來并集中到一個公共父類中以避免代碼重復(fù)。
- 需要通過子類來決定父類算法中某個步驟是否執(zhí)行计寇,實現(xiàn)子類對父類的反向控制锣杂。
2. 模式結(jié)構(gòu)與實例講解
2.1模式結(jié)構(gòu)
如模板方法模式結(jié)構(gòu)圖所知脂倦,有兩個類:
- AblstractClass(抽象類):在抽象類中定義了一系列的操作PrimitiveOperation,每個操作可以使具體的元莫,也可以是抽象的赖阻,每個操作對應(yīng)一個算法的步驟,在子類中可以重新定義或?qū)崿F(xiàn)這些步驟踱蠢。TmplateMethod()這個方法用于定義一個算法結(jié)構(gòu)火欧,模板方法不僅可以調(diào)用在抽象類中實現(xiàn)的基本方法,也可以調(diào)用在抽象類的子類中實現(xiàn)的基本方法朽基,還可以調(diào)用其他對象中的方法布隔。
- ConcreteClass(具體子類):用于實現(xiàn)在父類中聲明的抽象基本操作,也可以覆蓋在父類中已經(jīng)實現(xiàn)的具體基本操作稼虎。
2.2 實例講解
創(chuàng)建一個抽象模板結(jié)構(gòu)(AblstractClass)好父親
public abstract class AblstractClass {
//模板方法用來控制子類的順序 要想有人生必須按老爸的人生順序來
//聲明final不讓子類覆蓋這個方法谎势,防止改變?nèi)松樞? public final void 人生(){
學(xué)習(xí)();
工作();
愛情();
}
//家里窮更得用工學(xué)習(xí)
public void 學(xué)習(xí)(){
System.out.println("每天晚上趴在鄰居窗上學(xué)習(xí)");
}
//工作必須穩(wěn)定
public void 工作(){
System.out.println("從一而終");
}
//戀愛自由 讓兒子自由戀去
public abstract void 愛情();
}
創(chuàng)建一個具體模板(ConcreteClass)好兒子
public class ConcreteClass extends AblstractClass {
//兒子不認可父親的學(xué)習(xí)方法 考高分影響同學(xué)關(guān)系
@Override
public void 學(xué)習(xí)() {
System.out.println("60分萬歲...");
}
//父親給我愛情自由 一定好好談戀愛
@Override
public void 愛情() {
System.out.println("膚白貌美大長腿...");
}
}
調(diào)用他們的人生
public class TestMain {
public static void main(String[] args) {
ConcreteClass cs = new ConcreteClass();
cs.人生();
}
}
結(jié)果輸出
60分萬歲...
從一而終
膚白貌美大長腿...
3. 模式在Servlet中的應(yīng)用
3.1 自己實現(xiàn)一下
瀏覽器向服務(wù)端發(fā)送一個請求萤衰,常用請求方式有兩種,get請求和post請求仁堪,這兩種請求方式會導(dǎo)致請求參數(shù)在請求協(xié)議包(Http包)中的位置是不一樣的沉眶,那么請求協(xié)議包中不同的內(nèi)容到達服務(wù)端之后會有不同的對象進行處理打却,如請求頭的內(nèi)容由tomcat負責,請求體中的內(nèi)容由request負責谎倔,所以此時柳击,開發(fā)人員在拿到service()方法后考慮到它可以接受所有請求方式,因此會針對不同的請求方式封裝不同的請求方法片习。
建一個OneServlet 繼承GenericServlet捌肴,實現(xiàn)service()方法,需要重寫里面的doPost和doGet方法藕咏。
public class OneServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse arg1) throws ServletException, IOException {
//1.從協(xié)議包【請求行】中來讀取瀏覽器發(fā)送的請求方式
HttpServletRequest request = (HttpServletRequest)req;//一般來說由父類修飾的對象由子類來修飾對象状知,目的就是功能擴充
String method = request.getMethod();//POST GET
if("GET".equals(method)){
doGet(req, arg1);
}else if("POST".equals(method)){
doPost(req, arg1);
}
}
//處理瀏覽器發(fā)送的post請求
public void doPost(ServletRequest arg0, ServletResponse arg1){
//這里面是doPost封裝好的方法
System.out.println("doPost is run....");
}
//處理瀏覽器發(fā)送的get請求
public void doGet(ServletRequest arg0, ServletResponse arg1){
//這里面是doPost封裝好的方法
System.out.println("doGet is run....");
}
}
現(xiàn)在開發(fā)人員面臨的是,即需要做方法的實現(xiàn)孽查,有需要考慮service()方法在何時調(diào)用饥悴。在實際開發(fā)過程中service()方法里面是一段重復(fù)性的代碼,所有的servlet類實現(xiàn)中都需要寫這么一段重復(fù)性的代碼盲再,這樣重復(fù)的開發(fā)既增加工作量西设,又顯得代碼臃腫,降低了系統(tǒng)耦合度答朋。模板方法設(shè)計模式就是來解決這個問題的贷揽。下面看一下怎么解決。
建立MyHttpServlet類(就是模板方法設(shè)計模式中的父類)绿映,繼承GenericServlet類擒滑。
public class MyHttpServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//控制子類中的doGet和doPost方法
//1.從協(xié)議包【請求行】來讀取瀏覽器發(fā)送的請求方式
HttpServletRequest request = (HttpServletRequest)req;
String method = request.getMethod();//POST GET
if("GET".equals(method)){
doGet(req, res);//this.doGet()
}else if("POST".equals(method)){
doPost(req, res);
}
}
public void doPost(ServletRequest arg0, ServletResponse arg1){
}
public void doGet(ServletRequest arg0, ServletResponse arg1){
}
}
建立TwoServlet類,此時此刻開發(fā)人員不用去考慮何時調(diào)用doGet方法腐晾。當調(diào)用TwoServlet類的時候,tomcat一定是調(diào)用它的service()方法丐一。
/**
* Servlet implementation class TwoServlet
*/
public class TwoServlet extends MyHttpServlet {
//選擇是接受doGet方法還是doPost方法
@Override
public void doGet(ServletRequest arg0, ServletResponse arg1) {
System.out.println("ThreeServlet doGet is run...");
}
}
測試代碼localhost:8080/.../...
ThreeServlet doGet is run...
3.2 看HttpServlet源碼
HttpServlet也是繼承了GenericServlet 藻糖,跟蹤找到Service()方法,發(fā)現(xiàn)有兩個service()方法库车。
//這個方法是從它的父類GenericServlet繼承過來的
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response");
}
//分別對請求對象和響應(yīng)對象做了類型強轉(zhuǎn)巨柒。
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);//調(diào)用的是自己聲明的service方法,重載柠衍。
}
}
進入到自己聲明的service()方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();//讀取請求方式
if (method.equals(METHOD_GET)) {//根據(jù)請求方式調(diào)用對應(yīng)方法
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
發(fā)現(xiàn)service方法沒有使用final洋满,這是因為如果使用final修飾,就徹底斷絕了我們下游開發(fā)人員的開發(fā)珍坊,這樣是降低了系統(tǒng)的靈活度牺勾。
設(shè)計模式是問題解決思想(辦法),沒有固定的命令搭配 阵漏。
如果我們自己可以有這樣一些解決辦法驻民,那就是好的設(shè)計模式。