中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

做視頻播放網(wǎng)站百度問答庫

做視頻播放網(wǎng)站,百度問答庫,建設銀行衡陽市分行網(wǎng)站,前端seo優(yōu)化文章目錄 模板方法模式簡介作用模板方法模式的缺點模板方法模式的應用場景業(yè)務場景開源框架中的應用 對比回調(diào)和Hook模式關于組合優(yōu)先于繼承 關于設計模式亂用的現(xiàn)象 模板方法模式 簡介 模板方法模式是一種行為型設計模式,該設計模式的核心在于通過抽象出一套相對…

文章目錄

  • 模板方法模式
    • 簡介
    • 作用
    • 模板方法模式的缺點
    • 模板方法模式的應用場景
      • 業(yè)務場景
      • 開源框架中的應用
    • 對比回調(diào)和Hook模式
      • 關于組合優(yōu)先于繼承
    • 關于設計模式亂用的現(xiàn)象

模板方法模式

簡介

模板方法模式是一種行為型設計模式,該設計模式的核心在于通過抽象出一套相對標準的處理步驟,并可靈活的將任意步驟交給子類去進行擴展,使得可以在不改變整體業(yè)務處理流程的前提下,通過定義不同的子類實現(xiàn)即可完成業(yè)務處理的擴展。

我們可以舉個簡單的例子,比如對于下面定義的method方法中調(diào)用的a、b、c三個子方法,可以通過不同的子類實現(xiàn)來完成不同業(yè)務邏輯的處理。

public abstract class Temp {public final void method() {a();b();c();}protected abstract void c();protected abstract void b();protected abstract void a();}

還可以這樣定義,此時相當于b方法在父類中有一套默認的處理,子類可以根據(jù)需要選擇重寫或者不重寫。

public abstract class Temp {public final void method() {a();b();c();}protected abstract void c();protected void b() {// 默認處理邏輯。。。}protected abstract void a();}

當然,還可以將b方法聲明為private或者加上final關鍵字從而禁止子類重寫,此時b方法的邏輯就完全由父類統(tǒng)一管理。

public abstract class Temp {public final void method() {a();b();c();}protected abstract void c();private void b() {// 固定處理邏輯。。。}protected abstract void a();}

作用

模板方法模式主要有兩大作用:復用和擴展。

復用:復用指的是像method這樣的方法,所有子類都可以拿來使用,復用該方法中定義的這套處理邏輯。

擴展:擴展的能力就更加強大了,狹義上可以針對代碼進行擴展,子類可以獨立增加功能邏輯,而不影響其他的子類,符合開閉原則,廣義上可以針對整個框架進行擴展,比如像下面這段代碼邏輯:

public class Temp {public final void method() {a();b();c();d();}protected void c() {// 默認處理邏輯。。。};private void b() {// 固定處理邏輯。。。}protected void a() {// 默認處理邏輯。。。}protected void d() {// 強制子類必須重寫throw new UnsupportedOperationException();}}

框架默認可以直接使用,但同時也預留了a、cd三個方法的擴展能力,且d方法還通過拋出異常的方式,強制要求子類必須重寫,所以現(xiàn)在完全可以通過方法重寫的方式實現(xiàn)框架的功能擴展。
這種框架擴展的方式的典型案例就是Servlet中定義的service方法,該方法分別預留了doGetdoPost等擴展方法。

模板方法模式的缺點

從另一個角度來說,設計模式本身實際上并不存在什么缺點,真正導致出現(xiàn)這些問題的原因還是使用設計模式的方式,尤其是新手在剛了解到設計模式的時候,往往會試圖到處找場景去套用各種設計模式,甚至一個方法能用上好幾種,這就是典型的手里拿個錘子,看什么都是釘子。所以,如果按照這樣的使用方式,通常就會導致子類或者實現(xiàn)類非常多,但邏輯卻很少,或相似;方法為了兼容各種場景而過于抽象,導致代碼復雜度增加,可閱讀性也變差。

針對模板方式模式來說,因為通常情況下是通過繼承機制來實現(xiàn)業(yè)務流程的不變部分和可變部分的分離,因此,如果可變部分的業(yè)務邏輯并不復雜,或者不變部分和可變部分的關系不清晰時,就不適合用模板方法模式了。

模板方法模式的應用場景

業(yè)務的整體處理流程是固定的,但其中的個別部分是易變的,或者可擴展的,此時就可以使用模板方法模式,下面我們分別舉一些常見的業(yè)務場景和開源框架的應用來說明。

業(yè)務場景

訂單結(jié)算場景

訂單結(jié)算在電商平臺是非常常見的功能,整個結(jié)算過程一定會包含:訂單生成、庫存校驗、費用計算、結(jié)果通知,但比如其中費用計算則可能在優(yōu)惠券、折扣、運費等地方又有所不同,因此可以將整個結(jié)算過程抽象為一個模板類,具體的結(jié)算類只需要繼承該模板類,并實現(xiàn)具體的計算規(guī)則即可。

任務活動場景

常見的任務活動,主要包含三步驟:任務事件接收、任務規(guī)則匹配、任務獎勵觸發(fā),而往往事件接收和獎勵觸發(fā)都是比較統(tǒng)一的,規(guī)則匹配則跟具體的任務相關,所以可以用模板方法模式來實現(xiàn)。

開源框架中的應用

Spring MVC

handleRequestInternal由子類實現(xiàn)

public abstract class AbstractController extends WebContentGenerator implements Controller {@Override@Nullablepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {if (HttpMethod.OPTIONS.matches(request.getMethod())) {response.setHeader("Allow", getAllowHeader());return null;}// Delegate to WebContentGenerator for checking and preparing.checkRequest(request);prepareResponse(response);// Execute handleRequestInternal in synchronized block if required.if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {return handleRequestInternal(request, response);}}}return handleRequestInternal(request, response);}/*** Template method. Subclasses must implement this.* The contract is the same as for {@code handleRequest}.* @see #handleRequest*/@Nullableprotected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)throws Exception;}

MyBatis

BaseExecutorMyBatis中經(jīng)典的模板方法模式應用,其主要是用來執(zhí)行SQLquery方法是模板方法的主流程,doQuery方法是其留給子類實現(xiàn)的。

image.png

public abstract class BaseExecutor implements Executor {// 幾個do開頭的方法都是留給子類實現(xiàn)的protected abstract int doUpdate(MappedStatement ms, Object parameter)throws SQLException;protected abstract List<BatchResult> doFlushStatements(boolean isRollback)throws SQLException;protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)throws SQLException;protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)throws SQLException;  @Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);return query(ms, parameter, rowBounds, resultHandler, key, boundSql);}@SuppressWarnings("unchecked")@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());if (closed) {throw new ExecutorException("Executor was closed.");}if (queryStack == 0 && ms.isFlushCacheRequired()) {clearLocalCache();}List<E> list;try {queryStack++;list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;if (list != null) {handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);} else {list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {queryStack--;}if (queryStack == 0) {for (DeferredLoad deferredLoad : deferredLoads) {deferredLoad.load();}// issue #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list;}
}private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {List<E> list;localCache.putObject(key, EXECUTION_PLACEHOLDER);try {// 具體query方式,交由子類實現(xiàn)list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);} finally {localCache.removeObject(key);}localCache.putObject(key, list);if (ms.getStatementType() == StatementType.CALLABLE) {localOutputParameterCache.putObject(key, parameter);}return list;}

JDK AbstractCollection抽象類

AbstractCollection中實現(xiàn)了Set接口中定義的addAll方法,該方法又是基于add方法來實現(xiàn)的,具體代碼如下所示:

public boolean addAll(Collection<? extends E> c) {boolean modified = false;for (E e : c)if (add(e))modified = true;return modified;
}

AbstractCollection本身并不處理add方法,而是希望子類自己去實現(xiàn),如果調(diào)用者不小心直接調(diào)用了AbstractCollectionadd方法,則會直接拋出異常。

public boolean add(E e) {throw new UnsupportedOperationException();
}

對比回調(diào)和Hook模式

回調(diào)和Hook這兩種模式,在一定程度上也能起到模板方法模式的效果,他們都可以在一套流程中預留某個擴展點,然后將這個擴展點交由請求方自己來實現(xiàn),最常見的就是支付場景,在請求支付的時候,往往是不會同步等待支付結(jié)果的,而是在請求的同時注冊一個回調(diào)接口,這樣三方支付系統(tǒng)完成支付之后,就會回調(diào)這個接口來完成支付結(jié)果的通知。

雖然從應用場景上來回調(diào)或者Hook模式和模板方法模式差不多,但從代碼實現(xiàn)方式來看,卻有很大差異,模板方法模式是基于繼承的方式來實現(xiàn)的,這實際上是有很大的局限性,而回調(diào)或者Hook模式則是基于組合方式來實現(xiàn)的,我們都知道組合優(yōu)于繼承,其次,回調(diào)或者Hook模式還可以基于匿名類的方式來實現(xiàn),不用事先定義類,顯然更加靈活,當然,回調(diào)也有其問題,使用不當,容易出現(xiàn)調(diào)用關系混亂,系統(tǒng)層次混亂等現(xiàn)象。

關于組合優(yōu)先于繼承

繼承是實現(xiàn)代碼重用的重要手段之一,但并非是實現(xiàn)代碼重用的最佳方式,繼承打破了封裝性,因此很容易在使用時產(chǎn)生問題,為了更好的說明這一點,我們來舉個例子,假設我們現(xiàn)在需要為HashSet``添加一個計數(shù)功能,即看看HashSet自創(chuàng)建以來,一共被添加過多少個元素,我們可以用下面這種方式來實現(xiàn):

public class CountHashSet<E> extends HashSet<E> {private int addCount = 0;public CountHashSet() {}@Overridepublic boolean add(E e) {addCount++;return super.add(e);}@Overridepublic boolean addAll(Collection<? extends E> c) {addCount += c.size();return super.addAll(c);}public int getAddCount() {return addCount;}
}class Main {public static void main(String[] args) {CountHashSet<Integer> countHashSet = new CountHashSet<>();countHashSet.addAll(Arrays.asList(1, 2, 3));System.out.println(countHashSet.getAddCount());}
}

很遺憾最終輸出結(jié)果并不是3,而是6,問題就在于前面介紹的AbstractCollection關于addAll的實現(xiàn)方式,很明顯在addAll方法中調(diào)用add方法時被重復統(tǒng)計了,你不能因此說是addAll的實現(xiàn)方法有問題。

也許你只要像下面這段代碼一樣,就能修復這個問題,但這又依賴一個事實:addAll方法是在add方法中實現(xiàn)的,這實際上并不是什么標準,你也不能保證在之后的版本中不會發(fā)生變化。

public class CountHashSet<E> extends HashSet<E> {private int addCount = 0;public CountHashSet() {}@Overridepublic boolean add(E e) {addCount++;return super.add(e);}//    @Override
//    public boolean addAll(Collection<? extends E> c) {
//        addCount += c.size();
//        return super.addAll(c);
//    }public int getAddCount() {return addCount;}
}class Main {public static void main(String[] args) {CountHashSet<Integer> countHashSet = new CountHashSet<>();countHashSet.addAll(Arrays.asList(1, 2, 3));System.out.println(countHashSet.getAddCount());}
}

使用組合的方式

public class ForwardingSet<E> implements Set<E> {private final Set<E> s;public ForwardingSet(Set<E> s) {this.s = s;}@Overridepublic int size() {return s.size();}@Overridepublic boolean isEmpty() {return s.isEmpty();}@Overridepublic boolean contains(Object o) {return s.contains(o);}@Overridepublic Iterator<E> iterator() {return s.iterator();}@Overridepublic Object[] toArray() {return s.toArray();}@Overridepublic <T> T[] toArray(T[] a) {return s.toArray(a);}@Overridepublic boolean add(E e) {return s.add(e);}@Overridepublic boolean remove(Object o) {return s.remove(o);}@Overridepublic boolean containsAll(Collection<?> c) {return s.containsAll(c);}@Overridepublic boolean addAll(Collection<? extends E> c) {return s.addAll(c);}@Overridepublic boolean retainAll(Collection<?> c) {return s.retainAll(c);}@Overridepublic boolean removeAll(Collection<?> c) {return s.removeAll(c);}@Overridepublic void clear() {s.clear();}
}
class CountSet<E> extends ForwardingSet<E> {private int addCount = 0;public CountSet(Set<E> s) {super(s);}@Overridepublic boolean add(E e) {addCount++;return super.add(e);}@Overridepublic boolean addAll(Collection<? extends E> c) {addCount += c.size();return super.addAll(c);}public int getAddCount() {return addCount;}
}class Main {public static void main(String[] args) {CountSet<Integer> countHashSet = new CountSet<>(new HashSet<>());countHashSet.addAll(Arrays.asList(1, 2, 3));System.out.println(countHashSet.getAddCount());}
}

看吧,這就是使用組合的威力,組合更像是裝飾者模式,他可以在不改變原有類的功能的前提下,輕松實現(xiàn)功能的擴展,最重要的是,他比繼承要可靠的多。

關于設計模式亂用的現(xiàn)象

最后,再來聊聊關于設計模式亂用的問題,主要突出為以下兩個階段:

  1. 新手:這經(jīng)常發(fā)生在剛接觸設計模式不久的階段,急于找地方使用的情況,開發(fā)人員不考慮實際的業(yè)務場景,完全是為了用設計模式而用設計模式,甚至是先想好要用什么樣的設計模式,然后讓業(yè)務邏輯盡量往這個模式上去套。
  2. 勝任者:過了新手階段之后,此時你對設計模式也有一定使用經(jīng)驗了,開始意識到胡亂使用設計模式造成的問題了,懂得了理解業(yè)務場景才是關鍵,那還有什么問題呢?此時的階段就好比術和道的區(qū)別,術是多變的,就像我們常說的23種設計模式一樣,而道是不變的,無論哪種設計模式始終都是以幾種設計原則為依據(jù),正所謂萬變不離其宗,設計模式的使用不應當局限于形式上,要能靈活變換。
  3. 精通者:如果跨過新手階段的關鍵在于多寫多練的話,那么要跨過勝任者階段則要多思考了,得道的關鍵在于領悟。
http://www.risenshineclean.com/news/4448.html

相關文章:

  • 為什么網(wǎng)站有不同的擴展名全國最新的疫情數(shù)據(jù)
  • 鄒城手機網(wǎng)站建設重慶網(wǎng)
  • 煙臺網(wǎng)站排名優(yōu)化報價seo排名優(yōu)化課程
  • 購物網(wǎng)站開發(fā)費用武漢百度信息流廣告
  • wordpress后臺亂了是怎么回事專業(yè)網(wǎng)站優(yōu)化公司
  • 建立讀音seo研究中心vip教程
  • dw怎么做網(wǎng)站教程廣告推廣網(wǎng)站
  • seo的網(wǎng)站建設湖南企業(yè)競價優(yōu)化公司
  • 云技術在網(wǎng)站建設中的應用免費網(wǎng)絡推廣軟件
  • 模板手機網(wǎng)站建設公司濟南百度推廣優(yōu)化
  • 招遠建網(wǎng)站中國今天剛剛發(fā)生的新聞
  • 壽陽網(wǎng)站建設哈爾濱網(wǎng)絡推廣優(yōu)化
  • 想要找個網(wǎng)站做環(huán)評公示剛剛中國宣布重大消息
  • 讀書網(wǎng)站如何做職業(yè)技能培訓網(wǎng)
  • wap網(wǎng)站開發(fā) php網(wǎng)上銷售方法
  • 美妝網(wǎng)站建設環(huán)境分析人工在線客服系統(tǒng)
  • 做網(wǎng)站需要技術查詢關鍵詞排名軟件
  • 做網(wǎng)站的主機配置推銷產(chǎn)品怎么推廣
  • 海鹽市網(wǎng)站建設株洲專業(yè)seo優(yōu)化
  • 怎樣用c語言做網(wǎng)站北京seo推廣系統(tǒng)
  • 華為外包做的網(wǎng)站現(xiàn)在推廣引流什么平臺比較火
  • 湖北省利川市建設局網(wǎng)站企業(yè)網(wǎng)站優(yōu)化
  • 做網(wǎng)站排名工具如何讓產(chǎn)品吸引顧客
  • 可做區(qū)域代理的網(wǎng)站seo咨詢師
  • 泉州做網(wǎng)站的網(wǎng)上推廣渠道有哪些
  • 網(wǎng)絡營銷以什么為中心官網(wǎng)seo哪家公司好
  • 可以免費進入的網(wǎng)站正能量域名網(wǎng)址關鍵詞查詢網(wǎng)站
  • 在線下單網(wǎng)站怎么做網(wǎng)站seo診斷
  • 專業(yè)網(wǎng)站設計推薦百度云資源搜索
  • 給網(wǎng)站做引流多少錢2023年中國進入一級戰(zhàn)備狀態(tài)了嗎