4.2.3面向对象的开发方式有什么优点
这里只介绍三个优点:
1>较高的开发效率。采用面向对象的开发方式,可以对现实的事物进行抽象,可以把现实的事物直接映射为开发的对象,与人类的思维过程相似,例如设计一个Car类来表示现实中的汽车,这种方式直观明了,也非常接近人们的正常思维。同时,由于面向对象的开发方式可以通过继承或者组合的方式来实现代码的重用,因此可以大大的提高软件的开发效率。
2>保证软件的鲁棒性(鲁棒是Robus的音译,即健壮性)。正是由于面向对象的开发方法有很高的重用性,在开发过程中,可以重用已有的而且在相关领域经过长期测试的代码。因此,自然而然的对软件开发的健壮性起到了良好的作用。
3>保证软件的高可维护性。由于采用面向对象的开发方式,使得代码的可读性非常好,同时面向对象的设计模式也使得代码结构更加清晰明了。同时针对面向对象的开发方式,已有许多非常成熟的设计模式,这些设计模式可以使程序在面对需求变更是,只需要修改部分的模块就可以满足需求,因此维护起来非常方便。
4.2.4什么是继承
这一部分参见我前面的博客(http://blog.csdn.net/qq_28814687/article/details/72722792)
4.2.5组合和继承
示例如下:(参考网址:http://blog.csdn.net/qq_28814687/article/details/72722792)
要实现的目标:鸟(Bird)和狼(Wolf)都是动物(Animal),动物都有心跳(beat()),会呼吸(beat()),,会进食(eat()),但是鸟会fly(fly()),狼会奔跑(run()),用Java程序实现以上描述。
InheritTest.java 使用继承方式实现目标
CompositeTest.java 使用组合方式实现目标
InheritTest.java
class Animal{
private void beat(){
System.out.println("心脏跳动..");
}
protected void eat(){
System.out.println("只有进食,我才可以生存");
}
public void breath(){
beat();
System.out.println("吸一口气,呼一口气,呼吸中..");
}
}
//继承Animal,直接复用父类的breath()
class Bird extends Animal{
//重写父类的方法
@Override
protected void eat(){
System.out.println("我是鸟,我要吃虫子");
}
public void fly(){
System.out.println("我是鸟,在天空中自由的飞翔..");
}
}
class Wolf extends Animal{
public void run(){
System.out.println("我是狼,我在草原上快速奔跑");
}
}
public class InheritTest {
public static void main(String[] args){
Bird b = new Bird();
b.breath();
b.eat();
b.fly();
Wolf w = new Wolf();
w.breath();
//直接调用父类的方法
w.eat();
w.run();
}
}
CompositeTest.java
class Animal{
private void beat(){
System.out.println("心脏跳动..");
}
protected void eat(){
System.out.println("只有进食,我才可以生存");
}
public void breath(){
beat();
System.out.println("吸一口气,呼一口气,呼吸中..");
}
}
class Bird{
//定义一个Animal变量,以供组合之用
private Animal a;
public Bird(Animal a){
this.a = a;
}
//通过调用成员变量Animal的固有方法(a.breath())使新类具有想用的功能
public void breath(){
a.breath();
}
protected void eat(){
System.out.println("我是鸟,我要吃虫子");
}
//为新类增加新的方法
public void fly(){
System.out.println("我是鸟,在天空中自由的飞翔");
}
}
class Wolf{
private Animal a;
public Wolf(Animal a)
{
this.a = a;
}
public void breath(){
a.breath();
}
public void eat(){
a.eat();
}
public void run()
{
System.out.println("我是狼,我在草原上快速奔跑");
}
}
public class CompositeTest {
public static void main(String[] args)
{
//显示地创建被组合的对象实例a1
Animal a1 = new Animal();
//以a1为基础组合出新对象实例b
Bird b = new Bird(a1);
//新对象实例可以breath
b.breath();
//新对象可以eat
b.eat();
//新对象实例也可以fly
b.fly();
Animal a2 = new Animal();
Wolf w = new Wolf(a2);
w.breath();
w.eat();
w.run();
}
}
运行结果都是:
心脏跳动..
吸一口气,呼一口气,呼吸中..
我是鸟,我要吃虫子
我是鸟,在天空中自由的飞翔..
心脏跳动..
吸一口气,呼一口气,呼吸中..
只有进食,我才可以生存
我是狼,我在草原上快速奔跑
可以看到,组合和继承可以实现相同的功能,都允许在新的类中设置子对象。组合中的整体类和继承中的子类对应,局部类和继承中的父类对应。
两者区别在于:
组合是显式的,整体类调用局部类的方法,需要定义一个局部类对象作为自己的成员变量,如上例,在Bird和Wolf中,都有成员变量Animal,而且调用局部类的方法都是 局部类实例.局部类方法名,整体类不能修改整体类的方法;
而继承却是隐式,在类声明时,就直接用extends关键字,在子类中如果要修改父类的方法,直接在子类中声明和父类方法签名完全一样的方法,然后实现就可以了(只可以重写父类public和protected修饰的方法),而子类调用父类的方法就直接 子类实例.父类方法名就可以了。
从组合的局部类与整体类的称呼就可以看出来,组合适用于的是两个类属于互相包含的关系,即局部类是整体类一部分的,整体类有多个局部类,这种组合关系也被称为“has-a”关系;从继承的父类、子类的称呼看到,继承适用于两个类属于从属关系,即子类也是父类,这种关系称为“is-a”关系。
关于继承和组合的选择,遵循一下两点原则:
1>除非两个类是“is-a”关系,否则不要轻易用继承,因为过多的继承会破坏代码的可维护性,当父类被修改时,会影响到所有继承自它的子类,从而增加程序的维护难度与成本。
2>不要仅仅为了实现多态而使用继承,如果类之间没有“is-a”关系,可以通过实现接口与组合的方式达到相同的目的。这种方式比集成的方式拥有更好的可扩展性。
关于接口实现多态,参见http://blog.csdn.net/nvd11/article/details/41129935 讲的很清楚。
所以能使用组合,就尽量不要用继承。