如何利用設(shè)計(jì)模式+泛型編程設(shè)計(jì)RedisTemplate?

????一看到XXXTemplate,首先想到的是什么?對(duì),沒(méi)錯(cuò)!就是Spring框架的JdbcTemplate。那么我們來(lái)說(shuō)說(shuō)如何使用設(shè)計(jì)模式和泛型來(lái)實(shí)現(xiàn)一個(gè)JedisTemplate 。

模版方法模式

在模板模式(Template Pattern)中,一個(gè)抽象類(lèi)公開(kāi)定義了執(zhí)行它的方法的方式/模板。它的子類(lèi)可以按需要重寫(xiě)方法實(shí)現(xiàn),但調(diào)用將以抽象類(lèi)中定義的方式進(jìn)行。這種類(lèi)型的設(shè)計(jì)模式屬于行為型模式。

意圖:定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類(lèi)中。模板方法使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

主要解決:一些方法通用,卻在每一個(gè)子類(lèi)都重新寫(xiě)了這一方法。

何時(shí)使用:有一些通用的方法。

如何解決:將這些通用算法抽象出來(lái)。

關(guān)鍵代碼:在抽象類(lèi)實(shí)現(xiàn),其他步驟在子類(lèi)實(shí)現(xiàn)。

應(yīng)用實(shí)例:?

1、在造房子的時(shí)候,地基、走線(xiàn)、水管都一樣,只有在建筑的后期才有加壁櫥加?xùn)艡诘炔町悺?

2、西游記里面菩薩定好的 81 難,這就是一個(gè)頂層的邏輯骨架。?

3、spring 中對(duì) Hibernate 的支持,將一些已經(jīng)定好的方法封裝起來(lái),比如開(kāi)啟事務(wù)、獲取 Session、關(guān)閉 Session 等,程序員不重復(fù)寫(xiě)那些已經(jīng)規(guī)范好的代碼,直接丟一個(gè)實(shí)體就可以保存。

優(yōu)點(diǎn):?1、封裝不變部分,擴(kuò)展可變部分。 2、提取公共代碼,便于維護(hù)。 3、行為由父類(lèi)控制,子類(lèi)實(shí)現(xiàn)。

缺點(diǎn):每一個(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類(lèi)來(lái)實(shí)現(xiàn),導(dǎo)致類(lèi)的個(gè)數(shù)增加,使得系統(tǒng)更加龐大。

使用場(chǎng)景:?1、有多個(gè)子類(lèi)共有的方法,且邏輯相同。 2、重要的、復(fù)雜的方法,可以考慮作為模板方法。

注意事項(xiàng):為防止惡意操作,一般模板方法都加上 final 關(guān)鍵詞。

實(shí)現(xiàn)

我們將創(chuàng)建一個(gè)定義操作的?Game?抽象類(lèi),其中,模板方法設(shè)置為 final,這樣它就不會(huì)被重寫(xiě)。Cricket?和?Football?是擴(kuò)展了?Game?的實(shí)體類(lèi),它們重寫(xiě)了抽象類(lèi)的方法。

TemplatePatternDemo,我們的演示類(lèi)使用?Game?來(lái)演示模板模式的用法。




Java 泛型

Java 泛型(generics)是 JDK 5 中引入的一個(gè)新特性, 泛型提供了編譯時(shí)類(lèi)型安全檢測(cè)機(jī)制,該機(jī)制允許程序員在編譯時(shí)檢測(cè)到非法的類(lèi)型。


泛型的本質(zhì)是參數(shù)化類(lèi)型,也就是說(shuō)所操作的數(shù)據(jù)類(lèi)型被指定為一個(gè)參數(shù)。

假定我們有這樣一個(gè)需求:寫(xiě)一個(gè)排序方法,能夠?qū)φ蛿?shù)組、字符串?dāng)?shù)組甚至其他任何類(lèi)型的數(shù)組進(jìn)行排序,該如何實(shí)現(xiàn)?

答案是可以使用?Java 泛型。

使用 Java 泛型的概念,我們可以寫(xiě)一個(gè)泛型方法來(lái)對(duì)一個(gè)對(duì)象數(shù)組排序。然后,調(diào)用該泛型方法來(lái)對(duì)整型數(shù)組、浮點(diǎn)數(shù)數(shù)組、字符串?dāng)?shù)組等進(jìn)行排序。

泛型方法

你可以寫(xiě)一個(gè)泛型方法,該方法在調(diào)用時(shí)可以接收不同類(lèi)型的參數(shù)。根據(jù)傳遞給泛型方法的參數(shù)類(lèi)型,編譯器適當(dāng)?shù)靥幚砻恳粋€(gè)方法調(diào)用。

下面是定義泛型方法的規(guī)則:

所有泛型方法聲明都有一個(gè)類(lèi)型參數(shù)聲明部分(由尖括號(hào)分隔),該類(lèi)型參數(shù)聲明部分在方法返回類(lèi)型之前(在下面例子中的<E>)。

每一個(gè)類(lèi)型參數(shù)聲明部分包含一個(gè)或多個(gè)類(lèi)型參數(shù),參數(shù)間用逗號(hào)隔開(kāi)。一個(gè)泛型參數(shù),也被稱(chēng)為一個(gè)類(lèi)型變量,是用于指定一個(gè)泛型類(lèi)型名稱(chēng)的標(biāo)識(shí)符。

類(lèi)型參數(shù)能被用來(lái)聲明返回值類(lèi)型,并且能作為泛型方法得到的實(shí)際參數(shù)類(lèi)型的占位符。

泛型方法體的聲明和其他方法一樣。注意類(lèi)型參數(shù)只能代表引用型類(lèi)型,不能是原始類(lèi)型(像int,double,char的等)。


JedisTemplate實(shí)現(xiàn)

JedisTemplate是公司前輩封裝的一個(gè)redis包里的一個(gè)類(lèi),其實(shí)可以在很多地方看到類(lèi)似的封裝,并不復(fù)雜的類(lèi),這里借這個(gè)類(lèi)分享一下寫(xiě)代碼的技巧--簡(jiǎn)潔優(yōu)雅。

在這里能看到:

通過(guò)嵌套類(lèi)減少文件數(shù)量

模板方法設(shè)計(jì)模式如何減少重復(fù)代碼

泛型的寫(xiě)法,讓你少些類(lèi)和方法的利器

最重要的?。?!怎么提高碼代碼功力的方法----有基礎(chǔ)后,讀優(yōu)秀源碼,吸收模仿,最后隨心所欲的寫(xiě)。千萬(wàn)別止步于使用別人的代碼,難道你就不想品味


不啰嗦,上代碼

/**

* 提供對(duì)Redis常用命令的封裝,支持pipeline模式

*/

public class JedisStandAloneTemplate extends JedisTemplate {

private static Logger logger = LoggerFactory.getLogger(JedisStandAloneTemplate.class);

private JedisPool jedisPool;

public JedisStandAloneTemplate(JedisPool jedisPool) {

this.jedisPool = jedisPool;

}

/**

* Callback interface for template.

*/

// ==筆記1== 嵌套接口類(lèi),通常用于回調(diào),放在內(nèi)部能有效減少文件數(shù)量,降低閱讀障礙,而且主要是內(nèi)部使用。

// ==筆記2== 這里只是定義接口,通常配合模板方法使用。

//? ? ? 使用時(shí),new一個(gè)某種功能(get/del)的匿名實(shí)現(xiàn)類(lèi)作為參數(shù)傳入模板方法。

public interface JedisAction<T> {

// ==筆記3== jedis作為參數(shù),有模板方法提供,作為一種資源,無(wú)需定義一個(gè)類(lèi)屬性。

T action(Jedis jedis);

}

/**

* Callback interface for template without result.

*/

public interface JedisActionNoResult {

void action(Jedis jedis);

}

/**

* Execute with a call back action with result.

*/

// ==筆記4== 模板方法。通常用于消除冗余代碼,每個(gè)jedis調(diào)用都會(huì)涉及get連接,釋放連接,異常處理。

//? ? ? 唯一不同的地方是action,做的業(yè)務(wù)操作不同。

// ==筆記5== so我們把此業(yè)務(wù)操作抽象成一個(gè)接口,所有的具體業(yè)務(wù)操作類(lèi)實(shí)現(xiàn)此接口。

//? ? ? 為了簡(jiǎn)化代碼,我們使用匿名實(shí)現(xiàn)類(lèi)。為了簡(jiǎn)化使用,我們?cè)诖祟?lèi)暴露出使用優(yōu)化的方法(get/del)

// ==筆記6== 在此對(duì)外方法中,調(diào)用模板方法,new一個(gè)匿名實(shí)現(xiàn)類(lèi)作為入?yún)?,傳入模板方法,最終就像模板那樣。

//? ? ? 所有的公共操作都是一樣的,只有具體的業(yè)務(wù)操作被替換了。

// ==筆記7== 雖然看起來(lái)很好了,但是action接口返回值類(lèi)型是變化的,可能是String Boolean,我們不能定義很多action接口,

//? ? ? ? 所以這時(shí)要引入泛型編程<T>。接口類(lèi)是泛型接口interface JedisAction<T>,

//? ? ? ? 模板方法是泛型方法<T> T execute(JedisAction<T> jedisAction)。這里的<T>是限定符。

public <T> T execute(JedisAction<T> jedisAction) throws JedisException {

Jedis jedis = null;

try {

jedis = jedisPool.getResource();

return jedisAction.action(jedis);

} catch (JedisException e) {

throw e;

} finally {

closeResource(jedis);

}

}

/**

* Return the internal JedisPool.

*/

public JedisPool getJedisPool() {

return jedisPool;

}

protected void closeResource(Jedis jedis) {

try {

if (jedis != null) {

jedis.close();

}

} catch (Exception e) {

logger.error("return back jedis failed, will fore close the jedis.", e);

JedisUtils.destroyJedis(jedis);

}

}

@Override

public Boolean del(final String... keys) {

return execute(new JedisAction<Boolean>() {

@Override

public Boolean action(Jedis jedis) {

return jedis.del(keys) == keys.length ? true : false;

}

});

}

@Override

public String get(final String key) {

return execute(new JedisAction<String>() {

@Override

public String action(Jedis jedis) {

return jedis.get(key);

}

});

}

/**

* Get the value of the specified key as Long.If the key does not exist null is returned.

*/

@Override

public Long getAsLong(final String key) {

String result = get(key);

return result != null ? Long.valueOf(result) : null;

}

/**

* Get the value of the specified key as Integer.If the key does not exist null is returned.

*/

@Override

public Integer getAsInt(final String key) {

String result = get(key);

return result != null ? Integer.valueOf(result) : null;

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • “泛型”這個(gè)術(shù)語(yǔ)的意思是:"適用于許多許多的類(lèi)型”。如何做到這一點(diǎn)呢,正是通過(guò)解耦類(lèi)或方法與所使用的類(lèi)型之間的約束...
    王偵閱讀 1,352評(píng)論 0 0
  • object 變量可指向任何類(lèi)的實(shí)例,這讓你能夠創(chuàng)建可對(duì)任何數(shù)據(jù)類(lèi)型進(jìn)程處理的類(lèi)。然而,這種方法存在幾個(gè)嚴(yán)重的問(wèn)題...
    CarlDonitz閱讀 1,021評(píng)論 0 5
  • 蝸牛愛(ài)心閱讀 249評(píng)論 0 0
  • 原來(lái)憤怒來(lái)自伴侶關(guān)系,伴侶關(guān)系因?yàn)樾牟辉谝黄穑牟辉谝黄鹩质且驗(yàn)槭裁??源于不能信任,源于不安全感和孤?dú)感,而這又來(lái)...
    藝嫻閱讀 167評(píng)論 0 0
  • We willingly pay 30,000-40,000 fatalities per year for th...
    suntarliarzn閱讀 155評(píng)論 0 0

友情鏈接更多精彩內(nèi)容