【設計模式】模板設計模式與適配器設計模式

1、模板設計模式

趙本山問宋丹丹: “如何把大象放進冰箱?”宋丹丹回答:“第一步:打開冰箱門,第二步:把大象塞進 冰箱,第三步:關閉冰箱門”。趙本山再問:“怎麼把長勁鹿放進冰箱?”宋丹丹答: “第一步:打開冰箱門,第二步:把大象拿出來,第三步:把長勁鹿塞進去,第四步: 關閉冰箱門”(如下圖所示),這些都是模板模式的體現。

模板設計模式通常又叫做模板方法設計模式,是指定義個算法骨架,允許子類爲一個或者多個步驟提供實現。模板方法使得子類在不改變算法結構的情況下,重新定義算法的某些步驟,屬於行爲設計模式。

適用場景:

(1)一次性實現算法的不變部分,將可變的部分留給子類實現;

(2)各個子類中提取出公共行爲,向上提取到公共的父類中,從而實現 代碼複用。

模板模式在經典框架mybaties中的的應用:

BaseExecutor是一個基礎類,實現了大部分的SQL實行流程和邏輯,如獲取事物、關閉連接等,將處理不同的細節抽象,交給子類實現,下面是子類需要試下的抽象方法。

public abstract class BaseExecutor implements Executor {

    protected abstract int doUpdate(MappedStatement var1, Object var2) throws SQLException;

    protected abstract List<BatchResult> doFlushStatements(boolean var1) throws SQLException;

    protected abstract <E> List<E> doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException;

}

下面看看BaseExecutor的子類有那些?

下面看看doUpdate方法的實現

​
public class SimpleExecutor extends BaseExecutor {
    public SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;

        int var6;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            var6 = handler.update(stmt);
        } finally {
            this.closeStatement(stmt);
        }

        return var6;
    }
   .................
}

public class BatchExecutor extends BaseExecutor {
    public static final int BATCH_UPDATE_RETURN_VALUE = -2147482646;
    private final List<Statement> statementList = new ArrayList();
    private final List<BatchResult> batchResultList = new ArrayList();
    private String currentSql;
    private MappedStatement currentStatement;

    public BatchExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        BoundSql boundSql = handler.getBoundSql();
        String sql = boundSql.getSql();
        Statement stmt;
        if (sql.equals(this.currentSql) && ms.equals(this.currentStatement)) {
            int last = this.statementList.size() - 1;
            stmt = (Statement)this.statementList.get(last);
            BatchResult batchResult = (BatchResult)this.batchResultList.get(last);
            batchResult.addParameterObject(parameterObject);
        } else {
            Connection connection = this.getConnection(ms.getStatementLog());
            stmt = handler.prepare(connection);
            this.currentSql = sql;
            this.currentStatement = ms;
            this.statementList.add(stmt);
            this.batchResultList.add(new BatchResult(ms, sql, parameterObject));
        }

        handler.parameterize(stmt);
        handler.batch(stmt);
        return -2147482646;
    }
   ...............   
 }

public class ReuseExecutor extends BaseExecutor {
    private final Map<String, Statement> statementMap = new HashMap();

    public ReuseExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.update(stmt);
    }
   ................
}

​

JDK AbstractList 模板模式的應用:

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    abstract public E get(int index);

}


public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    transient Object[] elementData;

    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    E elementData(int index) {
        return (E) elementData[index];
    }
}

public class ArrayQueue<T> extends AbstractList<T> {
    public T get(int i) {
        int size = size();
        if (i < 0 || i >= size) {
            final String msg = "Index " + i + ", queue size " + size;
            throw new IndexOutOfBoundsException(msg);
        }
        int index = (head + i) % capacity;
        return queue[index];
    }
}

優點:

(1)將相同處理邏輯的代碼放入到父類中,提高代碼的複用性;

(2)處理不同細節的實現放在子類中,通過對子類擴展功能,提高代碼的擴展性;

(3)複合開閉原則

缺點:

(1)每個抽象類都需要子類實現,增加了類的個數;

(2)類個數的增加,導致系統複雜度提升;

(3)繼承自身的缺點,父類增加抽象方法,所有子類都要實現

思考:

     模板模式除了繼承方式以外,還有那些實現方式?

模板是的特點,流程標準化,處理細節不同,通過子類來擴展功能, 可以通過動態代理設計模式,

實現子類功能擴展,在子類方法前,調用固定流程方法實現,增強子類方法,從而實現模板設計模式的效果。

 

2、適配器設計模式

適配器模式是將一個接口轉換成另外一個接口,使原本不兼容的接口和類,可以工作,屬於結構性設計模式。

使用的業務場景:

(1)已經存在的類,方法和需求不匹配的情況‘

(1)一般情況下:適配器模式不是設計階段考慮的,而是系統更新升級,新的標準兼顧老版本使用。

如生活中的兩孔插頭轉三孔插頭; IPhone7的耳機孔標準採用了充電接口, 爲了讓Iphone6的圓孔耳機能夠在Iphone7上使用;居民用電220V,適配手機充電5V等。

適配器模式在軟件系統中的使用場景,如開始只有賬戶密碼登錄,現在升級支持三方登錄,兼容賬戶密碼登錄,如微信、QQ、支付寶、新浪等;

適配器在Spring中的應用:

(1)SpringAOP中AdvisorAdaptor與它的三個子類,MethodBeforeAdvisorAdaptor、AfterReturningAdviceAdapter、ThrowsAdviceAdapter

public interface AdvisorAdapter {
    boolean supportsAdvice(Advice var1);

    MethodInterceptor getInterceptor(Advisor var1);
}


class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    MethodBeforeAdviceAdapter() {
    }

    public boolean supportsAdvice(Advice advice) {
        return advice instanceof MethodBeforeAdvice;
    }

    public MethodInterceptor getInterceptor(Advisor advisor) {
        MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
        return new MethodBeforeAdviceInterceptor(advice);
    }
}

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
    AfterReturningAdviceAdapter() {
    }

    public boolean supportsAdvice(Advice advice) {
        return advice instanceof AfterReturningAdvice;
    }

    public MethodInterceptor getInterceptor(Advisor advisor) {
        AfterReturningAdvice advice = (AfterReturningAdvice)advisor.getAdvice();
        return new AfterReturningAdviceInterceptor(advice);
    }
}

class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {
    ThrowsAdviceAdapter() {
    }

    public boolean supportsAdvice(Advice advice) {
        return advice instanceof ThrowsAdvice;
    }

    public MethodInterceptor getInterceptor(Advisor advisor) {
        return new ThrowsAdviceInterceptor(advisor.getAdvice());
    }
}

(2)SpringMVC中的HandlerAdaptor類,與它的子類。

適配器調用關鍵代碼在DispatchServlet的doDospath()方法中,如以下源碼:

public class DispatcherServlet extends FrameworkServlet {

   .............
 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }

                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

   .............

}

getHandlerAdaptor()方法中循環調用了supports()方法判斷兼容性,迭代集合中Adaptor初始化是早已經複製。

優點:

(1)能提高類的透明性和複用

(2)目標類和適配器解耦,提供程序擴展性;

(3)複合開閉原則

缺點:

(1)適配器編寫過程中需要全面考慮,增加系統複雜性;

(2)增加代碼理解難度,降低代碼可讀性,過多使用適配器會使代碼混亂

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章