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

當(dāng)前位置: 首頁(yè) > news >正文

計(jì)算機(jī)辦公軟件培訓(xùn)班seo工程師招聘

計(jì)算機(jī)辦公軟件培訓(xùn)班,seo工程師招聘,不被看出wordpress開(kāi)發(fā),wordpress like 插件文章目錄 模板方法模式簡(jiǎn)介作用模板方法模式的缺點(diǎn)模板方法模式的應(yīng)用場(chǎng)景業(yè)務(wù)場(chǎng)景開(kāi)源框架中的應(yīng)用 對(duì)比回調(diào)和Hook模式關(guān)于組合優(yōu)先于繼承 關(guān)于設(shè)計(jì)模式亂用的現(xiàn)象 模板方法模式 簡(jiǎn)介 模板方法模式是一種行為型設(shè)計(jì)模式,該設(shè)計(jì)模式的核心在于通過(guò)抽象出一套相對(duì)…

文章目錄

  • 模板方法模式
    • 簡(jiǎn)介
    • 作用
    • 模板方法模式的缺點(diǎn)
    • 模板方法模式的應(yīng)用場(chǎng)景
      • 業(yè)務(wù)場(chǎng)景
      • 開(kāi)源框架中的應(yīng)用
    • 對(duì)比回調(diào)和Hook模式
      • 關(guān)于組合優(yōu)先于繼承
    • 關(guān)于設(shè)計(jì)模式亂用的現(xiàn)象

模板方法模式

簡(jiǎn)介

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

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

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

還可以這樣定義,此時(shí)相當(dāng)于b方法在父類(lèi)中有一套默認(rèn)的處理,子類(lèi)可以根據(jù)需要選擇重寫(xiě)或者不重寫(xiě)。

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

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

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

作用

模板方法模式主要有兩大作用:復(fù)用和擴(kuò)展。

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

擴(kuò)展:擴(kuò)展的能力就更加強(qiáng)大了,狹義上可以針對(duì)代碼進(jìn)行擴(kuò)展,子類(lèi)可以獨(dú)立增加功能邏輯,而不影響其他的子類(lèi),符合開(kāi)閉原則,廣義上可以針對(duì)整個(gè)框架進(jìn)行擴(kuò)展,比如像下面這段代碼邏輯:

public class Temp {public final void method() {a();b();c();d();}protected void c() {// 默認(rèn)處理邏輯。。。};private void b() {// 固定處理邏輯。。。}protected void a() {// 默認(rèn)處理邏輯。。。}protected void d() {// 強(qiáng)制子類(lèi)必須重寫(xiě)throw new UnsupportedOperationException();}}

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

模板方法模式的缺點(diǎn)

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

針對(duì)模板方式模式來(lái)說(shuō),因?yàn)橥ǔG闆r下是通過(guò)繼承機(jī)制來(lái)實(shí)現(xiàn)業(yè)務(wù)流程的不變部分和可變部分的分離,因此,如果可變部分的業(yè)務(wù)邏輯并不復(fù)雜,或者不變部分和可變部分的關(guān)系不清晰時(shí),就不適合用模板方法模式了。

模板方法模式的應(yīng)用場(chǎng)景

業(yè)務(wù)的整體處理流程是固定的,但其中的個(gè)別部分是易變的,或者可擴(kuò)展的,此時(shí)就可以使用模板方法模式,下面我們分別舉一些常見(jiàn)的業(yè)務(wù)場(chǎng)景和開(kāi)源框架的應(yīng)用來(lái)說(shuō)明。

業(yè)務(wù)場(chǎng)景

訂單結(jié)算場(chǎng)景

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

任務(wù)活動(dòng)場(chǎng)景

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

開(kāi)源框架中的應(yīng)用

Spring MVC

handleRequestInternal由子類(lèi)實(shí)現(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)典的模板方法模式應(yīng)用,其主要是用來(lái)執(zhí)行SQLquery方法是模板方法的主流程,doQuery方法是其留給子類(lèi)實(shí)現(xiàn)的。

image.png

public abstract class BaseExecutor implements Executor {// 幾個(gè)do開(kāi)頭的方法都是留給子類(lèi)實(shí)現(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方式,交由子類(lèi)實(shí)現(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抽象類(lèi)

AbstractCollection中實(shí)現(xiàn)了Set接口中定義的addAll方法,該方法又是基于add方法來(lái)實(shí)現(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方法,而是希望子類(lèi)自己去實(shí)現(xiàn),如果調(diào)用者不小心直接調(diào)用了AbstractCollectionadd方法,則會(huì)直接拋出異常。

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

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

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

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

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

繼承是實(shí)現(xiàn)代碼重用的重要手段之一,但并非是實(shí)現(xiàn)代碼重用的最佳方式,繼承打破了封裝性,因此很容易在使用時(shí)產(chǎn)生問(wèn)題,為了更好的說(shuō)明這一點(diǎn),我們來(lái)舉個(gè)例子,假設(shè)我們現(xiàn)在需要為HashSet``添加一個(gè)計(jì)數(shù)功能,即看看HashSet自創(chuàng)建以來(lái),一共被添加過(guò)多少個(gè)元素,我們可以用下面這種方式來(lái)實(shí)現(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,問(wèn)題就在于前面介紹的AbstractCollection關(guān)于addAll的實(shí)現(xiàn)方式,很明顯在addAll方法中調(diào)用add方法時(shí)被重復(fù)統(tǒng)計(jì)了,你不能因此說(shuō)是addAll的實(shí)現(xiàn)方法有問(wèn)題。

也許你只要像下面這段代碼一樣,就能修復(fù)這個(gè)問(wèn)題,但這又依賴一個(gè)事實(shí):addAll方法是在add方法中實(shí)現(xiàn)的,這實(shí)際上并不是什么標(biāo)準(zhǔn),你也不能保證在之后的版本中不會(huì)發(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());}
}

看吧,這就是使用組合的威力,組合更像是裝飾者模式,他可以在不改變?cè)蓄?lèi)的功能的前提下,輕松實(shí)現(xiàn)功能的擴(kuò)展,最重要的是,他比繼承要可靠的多。

關(guān)于設(shè)計(jì)模式亂用的現(xiàn)象

最后,再來(lái)聊聊關(guān)于設(shè)計(jì)模式亂用的問(wèn)題,主要突出為以下兩個(gè)階段:

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

相關(guān)文章:

  • 邯鄲做wap網(wǎng)站的公司百度雙十一活動(dòng)
  • 臨平網(wǎng)站建設(shè)互聯(lián)網(wǎng)營(yíng)銷(xiāo)推廣怎么做
  • 列舉網(wǎng)站開(kāi)發(fā)常用的工具電腦培訓(xùn)班速成班
  • 淘寶網(wǎng)站的建設(shè)目標(biāo)是北京百度seo排名點(diǎn)擊軟件
  • 佛山高明建網(wǎng)站都有什么推廣平臺(tái)
  • sns網(wǎng)站社區(qū)需求分析文檔百度廣告投放公司
  • 軟文推廣有哪些平臺(tái)seo外包方案
  • 網(wǎng)站建設(shè)內(nèi)部問(wèn)卷百度關(guān)鍵詞規(guī)劃師
  • 番禺有經(jīng)驗(yàn)的網(wǎng)站建設(shè)電商培訓(xùn)班一般多少錢(qián)
  • 做棋牌網(wǎng)站要什么源碼上海seo培訓(xùn)中心
  • 做網(wǎng)站流量的方法拼多多seo搜索優(yōu)化
  • 建設(shè)銀行網(wǎng)站登錄視頻號(hào)直播推廣二維碼
  • Php外貿(mào)網(wǎng)站建設(shè)新浪博客長(zhǎng)沙seo關(guān)鍵詞排名優(yōu)化
  • 佛山微網(wǎng)站建設(shè)seo新站如何快速排名
  • 網(wǎng)站建設(shè)崗位職責(zé)西安seo經(jīng)理
  • 全國(guó)網(wǎng)站建設(shè)公司排名無(wú)錫谷歌推廣
  • 如何做網(wǎng)校網(wǎng)站江蘇企業(yè)seo推廣
  • 做眾籌網(wǎng)站成都十大營(yíng)銷(xiāo)策劃公司
  • 杭州做網(wǎng)站的公司排行全國(guó)疫情高峰感染高峰
  • 深圳沙井做公司網(wǎng)站最近最新的新聞
  • woocommerce做零售網(wǎng)站網(wǎng)站排名推廣工具
  • 網(wǎng)站開(kāi)發(fā)需要有什么證書(shū)搜索引擎排名查詢工具
  • 大連自己的網(wǎng)站大數(shù)據(jù)營(yíng)銷(xiāo)專(zhuān)業(yè)
  • 做網(wǎng)站 怎么選擇公司今日新聞聯(lián)播主要內(nèi)容摘抄
  • 找別人做網(wǎng)站交貨時(shí)應(yīng)該注意什么禁止搜索引擎收錄的方法
  • 網(wǎng)站建設(shè)貳金手指科杰2如何做電商賺錢(qián)
  • 電子商務(wù)網(wǎng)站建設(shè)可用性深圳市seo網(wǎng)絡(luò)推廣哪家好
  • 建設(shè)政府網(wǎng)站多少錢(qián)青島seo關(guān)鍵詞排名
  • 建設(shè)部規(guī)范網(wǎng)站關(guān)鍵詞優(yōu)化的策略有哪些
  • 黃驊市第五中學(xué)北京seo推廣外包