詳解java抽象類和模板方法設(shè)計模式

原文http://kikoroc.com/2016/05/10/java-abstract-classes-and-template-method-design-pattern.html發(fā)表在我的個人博客。

java中的抽象類是不能被實例化的配紫,意味著你不能創(chuàng)建一個抽象類的實例午阵。抽象類的目的是為了作為子類的基類,本文將介紹如何在java中創(chuàng)建抽象類以及使用抽象類的一些規(guī)則底桂。

定義抽象類

java中定義抽象類很簡單,在類的定義中加入abstract關(guān)鍵字即可奋单。下面是java中定義抽象類的實例:

public abstract class MyAbstractClass {

}

上面就是java中定義抽象類的所有內(nèi)容猫十,現(xiàn)在你不能創(chuàng)建MyAbstractClass的實例,所以下面的代碼不再合法:

MyAbstractClass myClassInstance =
    new MyAbstractClass(); // not valid

如果你嘗試編譯上面的代碼拖云,編譯器將報錯,告訴你不能實例化MyAbstractClass宙项,因為它是一個抽象類。

抽象方法

抽象類中可以定義抽象方法汇荐,定義抽象方法也很簡單,在方法的定義前面添加abstract關(guān)鍵字即可掀淘,下面是定義抽象方法的實例:

public abstract class MyAbstractClass {
    public abstract void abstractMethod();
}

抽象方法是沒有具體實現(xiàn)細(xì)節(jié)的,僅僅是方法的定義倾贰,跟java interface中的方法類似。

如果一個類中包含抽象方法匆浙,那么這個類必須定義為abstract抽象類厕妖。但并不要求抽象類中所有方法都是抽象方法。抽象類中既可包含抽象方法也可以包含非抽象方法言秸。

抽象類的子類必須實現(xiàn)(override)父抽象類中所有的抽象方法,非抽象方法直接繼承到子類,如有需要也可以重寫非抽象方法破加。
下面是MyAbstractClass抽象類子類的實例:

public class MySubClass extends MyAbstractClass {
    public void abstractMethod() {
        System.out.println("My method implementation");
    }
}

注意MySubClass必須實現(xiàn)抽象父類MyAbstractClass中的抽象方法abstractMethod

抽象類的子類不用實現(xiàn)父類中的抽象方法唯一的情況是:子類也是抽象類合是。

抽象類的作用

抽象類的作用是為了作為子類的基類锭环,這樣子類很容易繼承父類來做具體的細(xì)節(jié)實現(xiàn)。比如辅辩,假如一個流程需要3個步驟:

  1. 具體動作之前的操作
  2. 執(zhí)行具體的動作
  3. 具體動作結(jié)束后的操作

如果第一步和第三步的實現(xiàn)總是相同的,那么這個三步走的流程可以用java抽象類這么實現(xiàn):

public abstract class MyAbstractProcess {
    public void process() {
        stepBefore();
        action();
        stepAfter();
    }

    public void stepBefore() {
        //直接在抽象父類中實現(xiàn)
    }

    public abstract void action(); // 由子類來實現(xiàn)

    public void stepAfter() {
        //直接在抽象父類中實現(xiàn)
    }
}

注意到action()方法是抽象方法蛾茉,MyAbstractProcess的子類現(xiàn)在可以繼承MyAbstractProcess然后重寫action()方法撩鹿。

當(dāng)子類的process()方法被調(diào)用,那么整個三步走的流程都會調(diào)用,包括父類中的stepBefore()stepAfter()方法以及子類中實現(xiàn)的action()方法础爬。

當(dāng)然吼鳞,MyAbstractProcess作為基類不一定非要是抽象類看蚜,action()也不是必須要是抽象方法的赖条,你可以直接使用普通類來實現(xiàn)同樣的邏輯,但是碱茁,讓具體的實現(xiàn)方法和類抽象化仿贬,你可以清晰的告訴使用者這個類不能直接使用,它應(yīng)該作為基類茧泪,然后讓子類來實現(xiàn)抽象方法。

上面實例中action()方法沒有默認(rèn)的實現(xiàn)队伟,是某些情況下父類也可以有默認(rèn)的實現(xiàn),子類也可以重寫該方法港令,當(dāng)然這種情況下這個方法就不能再定義為抽象方法锈颗,但是你依舊可以將類定義為抽象類,即使類里面沒有抽象方法击吱。

下面是一個更具體的實例用來打開一個URL,處理數(shù)據(jù)然后關(guān)閉鏈接朵纷。

public abstract class URLProcessorBase {

    public void process(URL url) throws IOException {
        URLConnection urlConnection = url.openConnection();
        InputStream input = urlConnection.getInputStream();

        try{
            processURLData(input);
        } finally {
            input.close();
        }
    }

    protected abstract void processURLData(InputStream input)
        throws IOException;

}

processURLData()是個抽象方法永脓,URLProcessorBase是個抽象類,那么URLProcessorBase的子類必須要實現(xiàn)父類的抽象方法processURLData()憨奸,因為它是一個抽象方法。

URLProcessorBase的子類可以直接處理url下載的數(shù)據(jù)似芝,而不用擔(dān)心如何打開和關(guān)閉url鏈接。因為這些都由父類實現(xiàn)了党瓮,子類只需要關(guān)注processURLData()方法中的InputStream對象,這樣可以使得可以很方便的實現(xiàn)url數(shù)據(jù)處理的子類呛谜。

下面是一個子類的實例:

public class URLProcessorImpl extends URLProcessorBase {

    @Override
    protected void processURLData(InputStream input) throws IOException {
        int data = input.read();
        while(data != -1){
            System.out.println((char) data);
            data = input.read();
        }
    }
}

注意到子類僅僅只需要重寫processURLData()方法枪萄,其他的方法直接從父類繼承過來。

下面是如何使用URLProcessorImpl類的實例:

URLProcessorImpl urlProcessor = new URLProcessorImpl();

urlProcessor.process(new URL("http://jenkov.com"));

父類URLProcessorBase中實現(xiàn)的process()方法直接調(diào)用聚凹,然后會調(diào)用URLProcessorImpl類中的processURLData()方法
齐帚。

抽象類和模板方法設(shè)計模式

上面的URLProcessorBase類的實例代碼實際上就是一種模板方法設(shè)計模式,模板方法設(shè)計模式提供了流程中一部分的實現(xiàn)邏輯湘今,然后子類可以繼承基類來完成全部的實現(xiàn)。


譯自:http://tutorials.jenkov.com/java/abstract-classes.html摩瞎,能力有限琅豆,詳細(xì)細(xì)節(jié)可以查閱原文篓吁。


模板方法設(shè)計模式簡述

上面提到抽象類和模板方法設(shè)計模式的關(guān)系,這里也簡單總結(jié)下模板設(shè)計方法冻押。

概述

定義一個操作中的算法框架盛嘿,而將具體的實現(xiàn)細(xì)節(jié)推遲到子類中實現(xiàn)。這樣可以使子類不改變算法結(jié)構(gòu)來重新定義算法的某些特定邏輯次兆。

角色

抽象類:實現(xiàn)模板方法,定義算法框架漓库。
具體類:實現(xiàn)抽象類中的抽象方法,完成完整的算法邏輯渺蒿。

優(yōu)缺點及適用場景

  1. 優(yōu)點
  • 模板方法通過將不變的行為在基類中實現(xiàn),去除了子類中的重復(fù)代碼怠蹂;
  • 在子類中負(fù)責(zé)具體的細(xì)節(jié)實現(xiàn)少态,有利于算法的擴(kuò)展;
  • 通過父類調(diào)用子類實現(xiàn)的操作况增,通過子類擴(kuò)展增加新的行為,符合“開閉原則”歧强。
  1. 缺點
    每個不同的實現(xiàn)都需要定義一個子類为肮,這會導(dǎo)致類個數(shù)的增加,設(shè)計更加抽象颊艳。
  2. 適用場景
  • 在某些類的算法中,用了相同的方法白修,造成代碼的重復(fù)重斑;
  • 控制子類的擴(kuò)展,子類必須遵守算法的框架規(guī)則窥浪。

代碼示例

抽象類:

public abstract class AbstractClass {
    // 定義算法的一些抽象行為,讓子類負(fù)責(zé)實現(xiàn)
    public abstract void step1();
    public abstract void step2();
    // 模板方法假颇,定義算法的框架骨稿,調(diào)用抽象方法姜钳,他們將在子類中實現(xiàn)形耗。
    public void TemplateMethod() {
        step1();
        step2();
        System.out.println("Completed.");
    }
}

具體類A:

public class ConcreteClassA extends AbstractClass {
    @Override
    public void step1() {
        System.out.println("step1 of ConcreteClassA");
    }
    @Override
    public void step2() {
        System.out.println("step2 of ConcreteClassA");
    }
}

具體類B:

public class ConcreteClassB extends AbstractClass {
    @Override
    public void step1() {
        System.out.println("step1 of ConcreteClassB");
    }
    @Override
    public void step2() {
        System.out.println("step2 of ConcreteClassB");
    }
}

調(diào)用:

AbstractClass abstractClass = new ConcreteClassA();
// 調(diào)用A的實現(xiàn)
abstractClass.TemplateMethod();

abstractClass = new ConcreteClassB();
// 調(diào)用B的實現(xiàn)
abstractClass.TemplateMethod();

輸出:

step1 of ConcreteClassA
step2 of ConcreteClassA
Completed.
step1 of ConcreteClassB
step2 of ConcreteClassB
Completed.

與抽象工廠模式的區(qū)別

模板方法是一種算法模板趟脂,針對算法的擴(kuò)展重寫泰讽;而抽象工廠模式是為了創(chuàng)建對象昔期,針對對象的擴(kuò)展重寫硼一。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市般贼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕊梧,老刑警劉巖腮介,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異甘改,居然都是意外死亡灭抑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門忘嫉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禀倔,“玉大人参淫,你說我怎么就攤上這事∠巡牛” “怎么了力九?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵邑闺,是天一觀的道長。 經(jīng)常有香客問我抵乓,道長靶衍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任蜈出,我火速辦了婚禮涛酗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘商叹。我一直安慰自己,他們只是感情好剖笙,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布枯途。 她就那樣靜靜地躺著,像睡著了一般酪夷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸥印,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天坦报,我揣著相機(jī)與錄音,去河邊找鬼潜的。 笑死字管,一個胖子當(dāng)著我的面吹牛啰挪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抽活,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锰什,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卵牍?” 一聲冷哼從身側(cè)響起沦泌,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谢谦,沒想到半個月后释牺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體回挽,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡千劈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涡驮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喜滨。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖虽风,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情无牵,我是刑警寧澤厂抖,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站验游,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏崔梗。R本人自食惡果不足惜垒在,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望场躯。 院中可真熱鬧,春花似錦伞鲫、人聲如沸签舞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至傍药,卻和暖如春魂仍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背擦酌。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留乙埃,地道東北人锯岖。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像遇伞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鸠珠,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計模式匯總 一、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用炬太、多...
    MinoyJet閱讀 3,944評論 1 15
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法驯耻,類相關(guān)的語法,內(nèi)部類的語法霎迫,繼承相關(guān)的語法,異常的語法知给,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • 1 場景問題# 1.1 登錄控制## 幾乎所有的應(yīng)用系統(tǒng)描姚,都需要系統(tǒng)登錄控制的功能,有些系統(tǒng)甚至有多個登錄控制的功...
    七寸知架構(gòu)閱讀 1,962評論 3 53
  • 設(shè)計模式基本原則 開放-封閉原則(OCP)谒主,是說軟件實體(類赃阀、模塊霎肯、函數(shù)等等)應(yīng)該可以拓展榛斯,但是不可修改。開-閉原...
    西山薄涼閱讀 3,797評論 3 14
  • Iterator模式 (迭代器) 一個一個遍歷 一個集合類可以遵守 Iterator 協(xié)議懂缕,并實現(xiàn)一個 Itera...
    SSBun閱讀 1,843評論 0 15