有一天,FHAM(FamilyHuAIMu)游戏团队队员小言说:接到一个活,需要咱们设计一款“鸭子群”游戏,大家开始讨论......
小胡:最简单的思路就是设计一个鸭子父类(鸭子祖类,父类中有红色,绿色,蓝色,铁鸭子,泥巴等属性,然后有游泳,吃喝拉撒睡等方法),然后然接下来的一群不同的鸭子分别继承这个父类,从而构造出我们自己的鸭子群(会飞的蓝鸭子,只会游泳不会飞的红鸭子等等)。大家便开始干并交付给用户。
(旁白)大家想一想这样一来会不会出现什么问题呢 过了一周......
小言:用户嫌弃咱们鸭子群的,反馈回来说:我想让我的鸭子飞上天,与太阳肩并肩......,要不直接给父类鸭子加上飞翔方法吧。行呀,交给你了,干掉他。
小胡:因为用的继承嘛,给那个鸭子父类加上飞方法后,鸭子们不久全都会飞了。不过,后来发现铁鸭子,泥巴鸭子也会飞了......由于违反常识,可能会带坏小朋友,咱们的鸭子群游戏被封杀了。
(旁白)所以得出一个结论,不能滥用继承
又过了一周,游戏团队队员小言觉得不甘心,说:“那不用继承了,咱们可以把鸭子父类中的飞翔呀,吃饭呀,睡觉呀,学习呀等等方法分别都封装为独立的接口,然后让之前的鸭子子类们谁需要什么方法,直接去父类中实现重写就行了呗,这总不会出错吧。”
(旁白)分开代码中常变化和不经常变化的部分---鸭子游戏,那就先分为两组呗
小胡:你意思是不是这样,把飞方法单独拿出来,放在一个飞接口中,然后算上鸭子父类,就有一个飞接口,一个鸭子父类。让鸭子群中谁想飞谁就来实现这个飞接口,并且重写接口中的飞方法。然后后期鸭子群中哪个子鸭子还想有父类鸭子中的哪个行为,咱就把父类鸭子中的那个方法继续拿出来放到一个接口中,让那个想要这个行为的子鸭子来实现这个接口并重写接口中的方法就行了。
小言:可以倒可以,不过要是这样干,那代码会不会有点浪费呢,一个类中只有一个方法
小胡:是可以有属性的,你想呀,最起码不谈另外的属性,就飞翔这个方法本身。你看飞翔的频率呀,翅膀的大小呀,飞翔的距离呀等等,都可以算作属性,用在类中呀,这不是目前用不到嘛。
小胡:对了,你看看我前几天看到的一个东西
public abstract class Duck{//这是鸭子父类
Fly f1;
public Duck(){}//鸭子父类的构造器
public void perform_fly(){
f1.fly//fly是上面那个飞接口中那个飞方法
}
}
public interface Fly{
public void fly();
}
public class Fly1 implemrnts Fly{
public void fly(){
......
}
}
public class DuckSon1 extends Duck{
public DuckSon1(){//这是鸭子子类1的构造器
f1 = new Fly1();
}
}
小言:看这样子,调用这个perform_fly方法就相当于调用那个飞接口的实现类中的那个飞翔方法了呀,这真是巧妙呀。
小胡:嗯,每次看到这个代码,就想吟诗一首:掬水月在手,弄花香满衣。这句我一直也挺喜欢的。
小言:而且,好像那个Fly就是咱们独立分离出来的含有飞方法的接口呀,而那个Fly1就是咱们Fly接口的一个实现类吧。
小胡:bingo...聪明呀,小伙子可以呀,偷走了我的脑纸吧你。
小胡:怕惊艳到你,来,再看
public abstract class Duck{//这是鸭子父类 Fly f1;
public Duck(){}//鸭子父类的构造器
public void perform_fly(){
f1.fly//fly是上面那个飞接口中那个飞方法
}
public void setFly(Fly f){
f2 = f;
}
}
小言:等等,你这好像是在父类鸭子中增加了一个setFly方法,然后就可以调用此方法,将那个接口传进来后,是不是就可以动态改变接口的实现类的那个飞行为了呢,好灵活呀。 小言:是不是这样
public class Test{
public static void main(){
Duck du = new DuckSon1()
du.perform_fly();
du.setFly(new DuckSon2)
du.perform_fly();
}
}
public class DuckSon2 extends Duck{
public DuckSon2(){//这是鸭子子类1的构造器
f2 = new Fly1();
}
}
小言:哦,你这就是相当于把鸭子子类1的飞行为改成了鸭子子类2的行为了呀,张冠李戴,那你两次du.perform_fly();出来的结果肯定不一样吧。
小胡:那肯定的喽。
小言:打哈欠...困啦,那收工吧,今天到此为止,明天再见。