開篇廢話
入職后一直研究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)出來,而是想告訴大家要有抽象分類的思想。