抽象類和接口的使用

開篇廢話

入職后一直研究Android framework的東西,大概花了一個(gè)月鼓搗了一個(gè)系統(tǒng)應(yīng)用“應(yīng)用雙開”。雖然也是敲代碼,但是主要是在Android源碼中進(jìn)行修改,也可以說很久沒用java去寫一個(gè)完整的東西了。近來公司有個(gè)小工具需要開發(fā),上頭應(yīng)該覺得功能很簡單,所以讓我一個(gè)人開發(fā)。具體功能需求不便透露,主要是一個(gè)windows應(yīng)用。本來我打算用C#寫,但是老大說最好用java,最終選了java swing來開發(fā)。這是一個(gè)很古老的東西,反正我也不熟悉,在大概學(xué)習(xí)了swing的組件使用之后,就開始動(dòng)手coding了。

java思想

其實(shí)不管java也好,其他面向?qū)ο笳Z言也好。面向?qū)ο蟮乃枷刖褪欠止ざ?,統(tǒng)一管理。這里我就不吹逼面向?qū)ο罅?,畢竟能力有限,吹逼能力有限,道行尚淺。大家記住這幾個(gè)字分工而治,統(tǒng)一管理。

例如

說一千道一萬,眼見為實(shí)耳聽為虛。我寫的工具中有這么一項(xiàng)需求。大致類似于,我要寫滿漢全席的食譜,總共一百零八道菜,每道菜都需要配圖(UI)和做法(文本),最終寫到一個(gè)冊(cè)子中(文本匯總)。

需求分析:

1.一百零八道菜,每個(gè)菜都不同,應(yīng)該對(duì)應(yīng)著有108個(gè)類吧。
2.每道菜都需要配圖和做法,對(duì)應(yīng)著每個(gè)類都應(yīng)該有一個(gè)pic()方法和cook()方法吧。
3.最終寫到一個(gè)冊(cè)子中。匯總:調(diào)用所有類的cook()方法,寫到一個(gè)文本中。

代碼設(shè)計(jì)

一定要記住,不要忙于寫代碼,而是搞清楚功能邏輯,不然寫到一半改需求是真的很要命,我就吃了這個(gè)虧,好在我前期代碼結(jié)構(gòu)設(shè)計(jì)還算可以,不至于重頭來過。

言歸正傳:108道菜,每道菜都不同,如果沒有重樣的菜,就意味應(yīng)該有108個(gè)類。每個(gè)類都有pic()和cook()方法,說明這是共用類,匯總的時(shí)候去調(diào)用每個(gè)類的cook()方法。
按照道理講功能的邏輯是這樣沒錯(cuò)了,如果這108類每個(gè)類都不一樣的話,這108類看來是必不可少了,pic()和cook(),屬于類的方法,無可厚非,但是匯總時(shí),我總不能把每個(gè)類都實(shí)例化一遍然后去調(diào)用各自的cook方法吧。所以這時(shí)候,java的抽象類和接口就得派上用場(chǎng)了。抽象類和接口都是用于類的繼承,抽象類只能單繼承,接口可以多繼承,這些基礎(chǔ)的概念,想必大家都懂,不懂沒關(guān)系,可以上網(wǎng)去查啊http://www.itdecent.cn/p/038f0b356e9a,
但是值得去講的是:抽象類和接口中都是抽象方法,就是沒有實(shí)現(xiàn)的方法,語法上支持你去調(diào)用這個(gè)方法,但是最終調(diào)用的是繼承了該類或接口并實(shí)現(xiàn)了該方法的類。
所以:我們可以這樣做,這些如何靈活運(yùn)行接口和抽象類就看各自的本事了,我大致講解一下我的做法。

首先我定義了一個(gè)抽象類
public abstract class Food {

    public String type = "";

    public Food() {
    }

    abstract public String cook();
    abstract public void pic();
}

其中有兩個(gè)未實(shí)現(xiàn)的抽象方法,因?yàn)榭紤]到108到菜也分菜系,所以用了type變量用來標(biāo)識(shí)菜系。
現(xiàn)在我們要做兩個(gè)菜系的菜,粵菜,和川菜。不管他們是哪個(gè)菜系,但是他們都屬于food,于是就呈現(xiàn)出一種繼承關(guān)系。

然后定義粵菜類和川菜類:
public abstract class YueCai extends Food {

    public YueCai() {
        type = "YueCai";
    }
}
public abstract class ChuanCai extends Food {

    public ChuanCai() {
        type = "ChuanCai";
    }
}

因?yàn)樗麄兪莊ood類的子類,所以他們也含有food類的pic()和cook()方法。
既然要寫成菜譜,那么我們是否應(yīng)該有一個(gè)專門來寫菜譜的人。

接著我們來定義cooker類
import java.util.List;

public class Cooker {

    private List<Food> foods = null;
    public Cooker() {
    }

    public void addFood(Food food) {
        foods.add(food);
    }

    public void write() {
        StringBuffer cookBook = new StringBuffer();
        for(Food food : foods) {
            cookBook.append(food.cook());
        }
    }
}

這里的cooker類,就是統(tǒng)一管理的類,首先是維護(hù)了一個(gè)List,類型是Food類,F(xiàn)ood是抽象類,就是告訴大家,我這里要裝的菜肴,但具體是什么菜,你實(shí)際放什么菜那就是什么菜,我這里不關(guān)心。
然后定義了add方法,用于往List中填充內(nèi)容,write()函數(shù),就是寫菜譜了,循環(huán)遍歷List<Food>,依次調(diào)用Food的cook方法。這里就解決了,108道,每道菜不同,不需要我分別調(diào)用這108個(gè)類的方法,因?yàn)槲以谶@里統(tǒng)一調(diào)用了抽象類Food的抽象方法cook(),但是這個(gè)方法是未實(shí)現(xiàn)的方法,所以它最終調(diào)用的是實(shí)現(xiàn)了這個(gè)方法的類。那么到底哪個(gè)類實(shí)現(xiàn)了該方法,而又是如何才能調(diào)用到的呢。

上面寫的所有的類都是代碼結(jié)構(gòu)的搭建,說白了就是一群只知道說,不去做事的家伙

那么我們來定義踏實(shí)干活的人吧

public class MapoDouFu extends ChuanCai{

    public MapoDouFu() {
    }

    @Override
    public String cook() {
        return "mapoDoufu";
    }

    @Override
    public void pic() {
        
    }

}

public class YanjuChicken extends YueCai {

    public YanjuChicken() {
    }

    @Override
    public String cook() {
        return "YanjuChicken";
    }

    @Override
    public void pic() {
        
    }

}

我們這里定義了兩道菜的類,一個(gè)MapoDoufu,一個(gè)YanjuChicken。他們分別繼承了ChuanCai類和YueCai類,而ChuanCai類和YueCai類都是繼承自Food類,所以他們都是Food類的子類。并且都是Food類的最終實(shí)現(xiàn)類。

然后我們?cè)诤线m的地方去調(diào)用Cooker的addFood()方法
Cooker cooker = new Cooker();
MapoDouFu mapoDouFu = new MapoDouFu();
cooker.addFood(mapoDouFu);
YanjuChicken yanjuChicken = new  YanjuChicken();
cooker.addFood(yanjuChicken);

這里就是java多態(tài)的體現(xiàn),我們定義addFood()方法時(shí),形式參數(shù)是Food類,但是在調(diào)用時(shí)實(shí)際傳入的Food類的子類MapoDoufu和YanjuChicken類。所以當(dāng)我們?nèi)フ{(diào)用wirte()時(shí),也將調(diào)用的實(shí)際傳入類的cook()方法。
這是簡單的對(duì)抽象類一個(gè)應(yīng)用場(chǎng)景的介紹,同樣,接口也是可以這樣使用的。原理是一樣的,我這里就不復(fù)述了。

public interface Food {
    public void pic();
    public String cook();
}
public class YanjuChicken implements Food {

    public YanjuChicken() {
    }

    @Override
    public void pic() {
        
    }

    @Override
    public String cook() {
        return "YanjuChicken";
    }

}
public class MapoDoufu implements Food {

    public  MapoDoufu() {
    }

    @Override
    public void pic() {
        
    }

    @Override
    public String cook() {
        return "MapoDoufu";

}
public class Cooker {

    private List<Food> foods = null;
    public Cooker() {
    }
    public void write() {
        StringBuffer cookBook = new StringBuffer();
        for(Food food : foods) {
            cookBook.append(food.cook());
        }
    }
    public void addFood(Food food) {
        foods.add(food);
    }

}

至于type的作用,本篇沒有體現(xiàn)出來,而是想告訴大家要有抽象分類的思想。

這里只涉及到接口和抽象類最基礎(chǔ)的用法,還有回調(diào),內(nèi)部類等等的用法,這些東西也是很常用的,后續(xù)我會(huì)更新相關(guān)的文章,如有錯(cuò)誤的地方,歡迎大家批評(píng)指正,不勝感激!如有疑惑的地方,也歡迎大家討論。

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 01接口的概念 02接口的定義 03接口的實(shí)現(xiàn)類 04接口中成員變量的特點(diǎn) 05接口中成員方法的特點(diǎn) 06實(shí)現(xiàn)類還...
    葡小萄家的貓閱讀 682評(píng)論 0 1
  • 你很清楚的知道什么時(shí)候用抽象類,什么時(shí)候用接口么?p.s. 多文字預(yù)警! 1 抽象類和接口簡介 1.1 抽象類 ...
    Sharember閱讀 2,424評(píng)論 9 55
  • 1、面向?qū)ο蟮奶卣饔心男┓矫?1.抽象:抽象就是忽略一個(gè)主題中與當(dāng)前目標(biāo)無關(guān)的那些方面,以便更充分地注意與當(dāng)前目標(biāo)...
    michaelgong閱讀 914評(píng)論 0 1
  • 第一次使用簡書,還不太清楚它會(huì)在我的生活中扮演什么角色,但是我深知行動(dòng)是解決問題的最好辦法。此刻,明天還要考試,我...
    jane1028閱讀 142評(píng)論 1 0
  • 2017年8月23日早6點(diǎn)半,聽完喜馬拉雅的易效能100講,我如以往打開印象筆記開始寫晨間日記。今天開心的看到晨間...
    田園成長閱讀 994評(píng)論 2 2

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