抽象类和接口的使用
开篇废话
入职后一直研究Android framework的东西,大概花了一个月鼓捣了一个系统应用“应用双开”。虽然也是敲代码,但是主要是在Android源码中进行修改,也可以说很久没用java去写一个完整的东西了。近来公司有个小工具需要开发,上头应该觉得功能很简单,所以让我一个人开发。具体功能需求不便透露,主要是一个windows应用。本来我打算用C#写,但是老大说最好用java,最终选了java swing来开发。这是一个很古老的东西,反正我也不熟悉,在大概学习了swing的组件使用之后,就开始动手coding了。
java思想
其实不管java也好,其他面向对象语言也好。面向对象的思想就是分工而治,统一管理。这里我就不吹逼面向对象了,毕竟能力有限,吹逼能力有限,道行尚浅。大家记住这几个字分工而治,统一管理。
例如
说一千道一万,眼见为实耳听为虚。我写的工具中有这么一项需求。大致类似于,我要写满汉全席的食谱,总共一百零八道菜,每道菜都需要配图(UI)和做法(文本),最终写到一个册子中(文本汇总)。
需求分析:
1.一百零八道菜,每个菜都不同,应该对应着有108个类吧。
2.每道菜都需要配图和做法,对应着每个类都应该有一个pic()方法和cook()方法吧。
3.最终写到一个册子中。汇总:调用所有类的cook()方法,写到一个文本中。
代码设计
一定要记住,不要忙于写代码,而是搞清楚功能逻辑,不然写到一半改需求是真的很要命,我就吃了这个亏,好在我前期代码结构设计还算可以,不至于重头来过。
言归正传:108道菜,每道菜都不同,如果没有重样的菜,就意味应该有108个类。每个类都有pic()和cook()方法,说明这是共用类,汇总的时候去调用每个类的cook()方法。
按照道理讲功能的逻辑是这样没错了,如果这108类每个类都不一样的话,这108类看来是必不可少了,pic()和cook(),属于类的方法,无可厚非,但是汇总时,我总不能把每个类都实例化一遍然后去调用各自的cook方法吧。所以这时候,java的抽象类和接口就得派上用场了。抽象类和接口都是用于类的继承,抽象类只能单继承,接口可以多继承,这些基础的概念,想必大家都懂,不懂没关系,可以上网去查啊http://www.jianshu.com/p/038f0b356e9a,
但是值得去讲的是:抽象类和接口中都是抽象方法,就是没有实现的方法,语法上支持你去调用这个方法,但是最终调用的是继承了该类或接口并实现了该方法的类。
所以:我们可以这样做,这些如何灵活运行接口和抽象类就看各自的本事了,我大致讲解一下我的做法。
首先我定义了一个抽象类
public abstract class Food {
public String type = "";
public Food() {
}
abstract public String cook();
abstract public void pic();
}
其中有两个未实现的抽象方法,因为考虑到108到菜也分菜系,所以用了type变量用来标识菜系。
现在我们要做两个菜系的菜,粤菜,和川菜。不管他们是哪个菜系,但是他们都属于food,于是就呈现出一种继承关系。
然后定义粤菜类和川菜类:
public abstract class YueCai extends Food {
public YueCai() {
type = "YueCai";
}
}
public abstract class ChuanCai extends Food {
public ChuanCai() {
type = "ChuanCai";
}
}
因为他们是food类的子类,所以他们也含有food类的pic()和cook()方法。
既然要写成菜谱,那么我们是否应该有一个专门来写菜谱的人。
接着我们来定义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类,就是统一管理的类,首先是维护了一个List,类型是Food类,Food是抽象类,就是告诉大家,我这里要装的菜肴,但具体是什么菜,你实际放什么菜那就是什么菜,我这里不关心。
然后定义了add方法,用于往List中填充内容,write()函数,就是写菜谱了,循环遍历List<Food>,依次调用Food的cook方法。这里就解决了,108道,每道菜不同,不需要我分别调用这108个类的方法,因为我在这里统一调用了抽象类Food的抽象方法cook(),但是这个方法是未实现的方法,所以它最终调用的是实现了这个方法的类。那么到底哪个类实现了该方法,而又是如何才能调用到的呢。
上面写的所有的类都是代码结构的搭建,说白了就是一群只知道说,不去做事的家伙
那么我们来定义踏实干活的人吧
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() {
}
}
我们这里定义了两道菜的类,一个MapoDoufu,一个YanjuChicken。他们分别继承了ChuanCai类和YueCai类,而ChuanCai类和YueCai类都是继承自Food类,所以他们都是Food类的子类。并且都是Food类的最终实现类。
然后我们在合适的地方去调用Cooker的addFood()方法
Cooker cooker = new Cooker();
MapoDouFu mapoDouFu = new MapoDouFu();
cooker.addFood(mapoDouFu);
YanjuChicken yanjuChicken = new YanjuChicken();
cooker.addFood(yanjuChicken);
这里就是java多态的体现,我们定义addFood()方法时,形式参数是Food类,但是在调用时实际传入的Food类的子类MapoDoufu和YanjuChicken类。所以当我们去调用wirte()时,也将调用的实际传入类的cook()方法。
这是简单的对抽象类一个应用场景的介绍,同样,接口也是可以这样使用的。原理是一样的,我这里就不复述了。
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的作用,本篇没有体现出来,而是想告诉大家要有抽象分类的思想。