1. 程式人生 > 其它 >nginx負載均衡+反向代理

nginx負載均衡+反向代理

定義

定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類可以不改變一個演算法的結構即可重新定義該演算法的某些特定步驟。
例如我們去銀行辦理業務,要經過取號、排隊、辦理具體業務等過程,取號、排隊對於每個客戶都是一樣的,可以在父類中實現,
辦理具體業務可能每個人都不同,可能是取款,存款,轉賬,這個操作可以延遲到子類中實現。

結構

  • AbstractClass,抽象類,用來定義演算法骨架
  • ConcreteClass,具體實現類,用來實現演算法骨架中的某些步驟,完成與特定子類相關的功能。

簡單實現

抽象類

public abstract class AbstractClass {

  public void operator() {
    beforeOperator();
    System.out.println("operator");
    afterOperator();
  }

  public abstract void beforeOperator();

  public abstract void afterOperator();
}

具體實現類

public class ConcreteClass extends AbstractClass {

  @Override
  public void beforeOperator() {
    System.out.println("ConcreteClass beforeOperator");
  }

  @Override
  public void afterOperator() {
    System.out.println("ConcreteClass afterOperator");
  }
}

模板方法模式在JDK和Servlet中的實現

JDK中實現

JDK中的AbstractList,AbstractMap

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
  //新增集合
  public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }
    //新增單個元素
    public boolean add(E e) {
        throw new UnsupportedOperationException();
    }

}

AbstractList中有很多模板方法,這裡我們就以addAll()方法為例,子類只需要實現add()方法就可以了。

Servlet中的實現

Servlet中的HttpServlet

public abstract class HttpServlet extends GenericServlet{
  protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            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);
        }
    }

  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException{
    }

   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException{
    }

HttpServlet的service方法定義整個演算法骨架,根據請求方法來做相應的處理,比如請求方法為GET,就呼叫doGet方法來處理,子類只需要重寫這些方法就可以了。

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    resp.getWriter().println("hello");
  }
}

總結

優點

  1. 將公共的功能提取到了父類中,實現了程式碼的複用。
  2. 將不變的部分封裝到父類中,可變部分由子類繼承實現,便於子類繼續擴充套件。

缺點

  1. 演算法骨架不容易升級,可能會影響所有相關的子類。

本質

模板方法模式的本質是固定演算法骨架。通過固定演算法骨架來約束子類的行為,並在特定的擴充套件點來讓子類進行功能擴充套件,
從而讓程式既有很好的複用性,又有較好的擴充套件性。

使用場景

  1. 各個子類中有公共行為,為了避免程式碼重複,應該提取到父類實現。
  2. 需要固定演算法骨架,並要子類來實現一些可變的部分。

參考

大戰設計模式【11】—— 模板方法模式
設計模式的征途—17.模板方法(Template Method)模式
設計模式(十四)——模板模式(SpringIOC原始碼分析)
設計模式——模板方法模式
模板方法模式(模板方法設計模式)詳解
研磨設計模式-書籍