
扯了一些有的没的,那么抽象类这个东西究竟在什么场景下用到呢?下面进入正题
以笔者自身为例,由于家里没矿,所以只能老老实实当个打工仔嘛,所以站在笔者老板的角度来看,笔者的身份就是个小员工嘛,老板雇你来干嘛呢,干活呗,于是就可以用以下接口来描述笔者以及笔者的同事们
public interface Employee {
void work();
}看到这里可能会说,员工怎么定义成接口,而且只有一个工作方法,连姓名啥的都不配有?真就工具人呗? 莫急莫急,当然配拥有姓名,我们打工仔也是有尊严的好吗!我们将姓名、年龄、性别这些基本属性定义在以下的Person类中
public class Person {
protected String name;
protected Integer age;
protected String gender;
public Person(String name, Integer age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}那为什么要这样定义呢,我们都知道JAVA中接口其实像是一个行为的约束与规范嘛,实现接口的类就必须要实现它当中的方法,那么对于你的老板而言,对你最大的关注点自然在你干不干活嘛,哪管你的姓名、年龄、性别呢?(哈哈,开个玩笑,开个玩笑~)
接着说,一个公司都有很多岗位嘛,什么人资呀会计呀等等,每个员工都有自己的岗位,那笔者自己是个程序员嘛,以程序员这个岗位为例,按照能力来划分又可以初级程序员、高级程序员等等。有的看官看到这可能又要急了,你扯这些乱七八糟的岗位和职级,和抽象类有什么关系呀?你这不是典型的“标题党”吗?!莫急,且往下看……
刚才说了程序员是员工中的一种,如果要用一个类来描述程序员的话,那自然实现员工接口,同时程序员也具备姓名和年龄等属性,因此还需要继承Person类。刚才也说了,员工嘛,干活才是重点。那么程序员平时是怎么工作的呢?我姑且简单将它分为两步1.写代码2.提交代码,这么一来我们可以用以下的代码来描述程序员
public class Programmer extends Person implements Employee {
public Programmer(String name, Integer age, String gender) {
super(name, age, gender);
}
@Override
public void work() {
coding();
submitCode();
}
private void coding(){
System.out.println("写代码");
}
private void submitCode(){
System.out.println("提交代码到git仓库");
}
}看到这里,好像都结束了,用上面的类来定义一个程序员,活也干了,名字年龄性别也有了,完美! 怎么可能呢?我们本篇的主角抽象类都还没出场呢!
刚才也说了,程序员是分职级的,有专写bug的菜鸟程序员,也有能写架构的高级程序员,那如果我们要分别用类来描述高级程序员和菜鸟程序员,该如何定义呢?其实简单,上文提到,程序员干活,简单来说就两个步骤,写代码和提交代码。而菜鸟程序员和高级程序员的主要的区别其实就在写代码这一环,因为提交代码就是一个git命令的事,对所有程序员都一样。那么说到这里了,到底该怎样才好呢?首先,将上文提到的Programmer类做一些修改,如下
public abstract class Programmer extends Person implements Employee{
public Programmer(String name, Integer age, String gender) {
super(name, age, gender);
}
@Override
public void work() {
coding();
submitCode();
}
protected abstract void coding();
protected void submitCode(){
System.out.println("提交代码到git仓库");
}
}可以看到,我将Programmer类改成了抽象类,并将coding(写代码)方法改成了抽象的,原因刚才说了,不同职级的程序员写代码的具体实现是不同的,因此抽象出来交给具体子类(各职级的程序员)去实现。此外还修改了方法的修饰符,方便继承。这么一来,我们的菜鸟程序员和高级程序员就很容易用类来描述了,代码如下
高级程序员:
public class SeniorProgrammer extends Programmer {
public SeniorProgrammer(String name, Integer age, String gender) {
super(name, age, gender);
}
@Override
protected void coding() {
System.out.println("写架构");
}
}菜鸟程序员:
public class NoobProgrammer extends Programmer {
public NoobProgrammer(String name, Integer age, String gender) {
super(name, age, gender);
}
@Override
protected void coding() {
System.out.println("写bug");
}
}接下来我们写个Main方法来测试一下
public class Main {
public static void main(String[] args) {
Employee shenao=new SeniorProgrammer("申奥",23,"mail");
Employee pengfei=new NoobProgrammer("鹏飞",24,"femail");
shenao.work();
System.out.println("------------分隔符-------------");
pengfei.work();
}
}运行结果如下:

这么一来,一切就都搞定啦!
看到这里,可能还是有的看官没有明白,抽象类到底在什么场景下使用呢?所谓抽象类,顾名思义,核心就在“抽象“二字,那么又该如何抽象呢?在笔者看来可以分为以下几个步骤:
首先,我们在根据业务来设计接口的时候,要搞清楚接口应该具备哪些行为(方法),再思考一下接口的这些行为是否可以细分成多个小行为,如果可以,那么就在接口与接口的实现类的中间添加一层抽象类,将这些相同的小行为具体的写在抽象类中,将那些不同的小行为定义成抽象,交给具体实现类去实现。当然,各个实现类中如果有相同的属性,同样也可以定义在抽象类中去。用我自己总结出来的一句话来描述就是:抽象类用于“具象”各个具体实现类中的最大公共部份,抽象各个实现类的差异部份。不知道我这样描述,看官们是否能够理解……
其实看完我上面的代码,有的看官可能会发现它与设计模式中的模板方法极其相似。是的,本文看似在写抽象类,其实是想用此来引发一个思考:在某些业务场景下,如何能够更好的对类进行设计,如何设计能够让自己的代码拓展性更强,可读性更高,而抽象类只不过是其中的一个手段而已。我认为,对于一个上进的程序员而言,“如何设计出更好的代码”将会是个职业生涯都在思考的问题……
文末,灵魂拷问:今天的你,比昨天更强了吗?如果没有,明天请努力!我是野原鑫之助,一个爱唱歌的菜鸟小码农,我们下期见……