打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
再论组合与继承
在本书中,把UML中的关联关系和聚集关系统称为组合关系。组合与继承都是提高代码可重用性的手段。在设计对象模型时,可以按照语义来识别类之间的组合关系和继承关系。在有些情况下,采用组合关系或者继承关系能完成同样的任务,组合和继承存在着对应关系:组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应,参见表6-1。本章6.9节(小结)中的表6-2总结了组合与继承的优缺点。
表6-1 组合与继承的对应关系
组 合 关 系
继 承 关 系
局部类
父类
整体类
子类
从整体类到局部类的分解过程
从子类到父类的抽象过程
从局部类到整体类的组合过程
从父类到子类的扩展过程
的聚集关系中的整体类和局部类具有更广泛的含义。在本章中,如果在类A中包含类C类型的属性,那么就把类A称为整体类或者包装类,把类C称为局部类或者被包装类。
组合关系的分解过程对应继承关系的抽象过程
图6-11 具有相同行为的类A和类B
下面的例子未涉及具体的业务领域,该例子分别用组合关系与继承关系来建立一个对象模型。如图6-11所示,类A和类B有相同方法method1()、method2()和method3(),此外类A和类B还分别拥有methodA()和methodB()方法。在method3()方法中访问method1()方法,在mehodA()和methodB()方法中都会访问method2()方法。以下是类A和类B的源程序。
view plaincopy to clipboardprint?
public class A{
private void method1(){System.out.println("method1");}
private void method2(){System.out.println("method2");}
public void method3(){method1();System.out.println("method3");}
public void methodA(){method2();System.out.println("methodA");}
}
public class B{
private void method1(){System.out.println("method1");}
private void method2(){System.out.println("method2");}
public void method3(){method1();System.out.println("method3");}
public void methodB(){method2();System.out.println("methodB");}
}
图6-12 从类A和类B中抽象出父类C
1.使用继承关系
在图6-12中,从类A和类B中抽象出父类C,它包含method1()、method2()和method3()方法。由于在类A和类B中都会访问method2()方法,因此把method2()方法声明为protected类型。
view plaincopy to clipboardprint?
public class C{
private void method1(){System.out.println("method1");}
protected void method2(){System.out.println("method2");}
public void method3(){method1();System.out.println("method3");}
}
public class A extends C{
public void methodA(){method2(); System.out.println("methodA");}
}
public class B extends C{
public void methodB(){method2(); System.out.println("methodB");}
}
2.使用组合关系
在图6-13中,类A与类C,以及类B与类C之间为组合关系。在类A中定义了C类型的引用变量c,类A的method3()方法直接调用类C的method3()方法。类A对类C进行了封装,类A被称为包装类,同样,类B也是包装类。由于在类A和类B中都会访问private类型的method2()方法,因此不能把method2()方法放在类C中定义,因为如果这样做,就必须在类C中把method2()方法定义为public类型,而这彻底破坏了封装。以下是类C、类A和类B的源程序。
view plaincopy to clipboardprint?
public class C{
private void method1(){System.out.println("method1");}
public void method3(){method1();System.out.println("method3");}
}
public class A {
private C c;
public A(C c){this.c=c;}
private void method2(){System.out.println("method2");}
public void method3(){c.method3();}
public void methodA(){method2(); System.out.println("methodA");}
}
public class B {
private C c;
public B(C c){this.c=c;}
private void method2(){System.out.println("method2");}
public void method3(){c.method3();}
public void methodB(){method2(); System.out.println("methodB");}
}
图6-13 从类A与类B中分解出局部类C
组合关系和继承关系相比,前者的最主要优势是不会破坏封装,当类A与类C之间为组合关系时,类C封装实现,仅向类A提供接口;而当类A与类C之间为继承关系时,类C会向类A暴露部分实现细节。在软件开发阶段,组合关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于组合关系使系统具有较好的松耦合性,因此使得系统更加容易维护。
组合关系的缺点是比继承关系要创建更多的对象。以下程序演示在两种关系下创建类A的实例并且调用其methodA()方法。
view plaincopy to clipboardprint?
//类A与类C为组合关系
C c=new C();
A a=new A(c);
a.methodA();
// 类A与类C为继承关系
A a=new A();
a.methodA();
从以上程序看出,对于组合关系,创建整体类的实例时,必须创建其所有局部类的实例;而对于继承关系,创建子类的实例时,无须创建父类的实例。继承关系最大的弱点是打破了封装,子类能够访问父类的实现细节,子类与父类之间紧密耦合,子类缺乏独立性,从而影响了子类的可维护性。为了尽可能地克服继承的这一缺陷,应该遵循以下原则:
·精心设计专门用于被继承的类,继承树的抽象层应该比较稳定。
·对于父类中不允许覆盖的方法,采用final修饰符来禁止其被子类覆盖。
·对于不是专门用于被继承的类,禁止其被继承。
·优先考虑用组合关系来提高代码的可重用性。
本章对组合关系和继承关系进行了比较,表6-2对这两种关系的优缺点做了总结。
表6-2 比较组合关系与继承关系
组 合 关 系
继 承 关 系
优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立
缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
优点:具有较好的可扩展性
缺点:支持扩展,但是往往以增加系统结构的复杂度为代价
优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象
缺点:不支持动态继承。在运行时,子类无法选择不同的父类
优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口
缺点:子类不能改变父类的接口
缺点:整体类不能自动获得和局部类同样的接口
优点:子类能自动继承父类的接口
缺点:创建整体类的对象时,需要创建所有局部类的对象
优点:创建子类的对象时,无须创建父类的对象
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Nirvana Studio Blog Archive cglib 指南 :: 分享知...
.net面试题3
B继承A A a=new B();B a=new B()区别
C#中A a=new B()的意义
关于java异常处理的几个关键字 try catch/throw/throws
开发项目中碰见异常情况怎么办?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服