Chapter3 继承

需要继承的原因

  • 它支持更丰富、更强大的建模。类之间联系更紧密,结构更清晰。在画UML图时重复的属性、函数就可以省略
  • 使得子类可以共享父类的一些定义
  • 从面向对象的角度来说,继承是自然的

设计类的层次结构

首先确定层次结构底部有哪些类,接着找出一般的概念,以丰富模型、共享元素的定义

共享的方法,放置的层次越高越好

以四个集合类为例,设计层次结构

四类集合:

List:把所有的对象按照插入的顺序放置

Bag:该集合中的对象没有排序

LinkedList:链表

ArrayList:该集合中的对象使用数组排序

按照集合中的对象有序/无序进行分层

将下面三个消息放到层次结构中

contains(:Object):是否包含该对象

elementAt(:int):在参数指定的位置检索对象

numberOfElements():返回集合中的对象数

elementAt要把位置作为参数,所以它必须处理有顺序的对象。故消息放置情况如下:

抽象类

抽象方法:没有具体实现

抽象类至少要有一个抽象方法。它可以是该类本身的方法,也可以是从父类继承来的。

大多数面向对象的语言都禁止创建抽象类的实例。

继承层次结构是如何自底向上派生的

  1. 在问题域中查找具体的概念,推导它们的知识和行为
  2. 在具体的类中找出共同点,以便引入更一般的超类
  3. 把超类组合到更一般的超类中,直至找出最一般的根类为止

大多数情况下,超类都是抽象的

继承具体的类改变其中已有的元素,以此完成我们希望的任务。这样有一个缺陷:已有的代码无法创建改进类的实例

重定义(override)

重定义的原因:

  • 继承的方法是抽象的
  • 子类中的方法需要完成一些额外的工作
  • 子类可以有更好的实现方法

在重定义时,应确保超类定义仍完成它以前完成的工作,这提高了代码共享性,简化了维护。每种面向对象的语言都允许重定义的方法调用超类上的方法

实现栈类

Stack类中需要有以下四个消息:

push():把对象添加到栈的顶部

peek():返回栈顶的对象

isEmpty():栈是否为空

pop():从栈顶删除一个对象

对比LinkedList类中,有相似的消息

addElement():在列表的尾部添加一个对象

lastElement():返回列表尾部的对象

numberOfElement():返回列表中的对象数

removeLastElement():删除列表尾部的对象

因此,我们把已有的LinkedList行为融合到新的Stack类中就可以了

使用继承实现

public class Stack extends LinkedList
{
	public void push(Object o)
	{
		addElement(o);
	}
	
	public Object peek()
	{
		return lastElement();
	}
	
	public boolean isEmpty()
	{
		return numberOfElement() == 0;
	}
	
	public Object pop()
	{
		Object o = lastElement();
		removeLastElement();
		return o;
	}
}

这样实现有一个严重的问题:LinkedList有一些消息是不适合栈的,例如firstElement()。用户可能通过这个方法把栈底部的元素给删除了,这是严重错误的。 

使用复合实现

 上图显示的Stack带有对LinkedList的引用。Stack将其行为委托给LinkedList,它对LinkedList的唯一引用在内部。

使用复合实现的Stack如下:

public class Stack
{
	private LinkedList list;
	
	public Stack()
	{
		list = new LinkedList();
	}
	
	public void push(Object o)
	{
		list.addElement(o);
	}
	
	public Object peek()
	{
		return list.lastElement();
	}
	
	public boolean isEmpty()
	{
		return list.numberOfElement() == 0;
	}
	
	public Object pop()
	{
		Object o = list.lastElement();
		list.removeLastElement();
		return o;
	}
}

使用复合实现,Stack类中必须声明和创建一个字段,其方法必须引用该字段。

复合的优点

复合会得到与继承相同的结果(具体类、具体消息和重用已有的代码),但相比于继承有以下优点

  • 较容易开发
  • 发现设计不足时容易改变
  • 客户容易理解
  • 不会泄露给客户代码

私有继承

私有继承也称实现继承,允许一个类继承另一个类,而继承的元素无需成为新接口的一部分。通过私有继承的类可以直接访问需要的方法,不必引入委托。但同时因为继承是私有的,客户不能使用部分不合适的消息。

多重继承

多重继承中,每个类可以有任意多个父类,综合几种继承层次结构的优点

优点:

允许私有继承

更接近真实情况。现实中,物品往往有多种分类标准,类也是如此

允许混合继承。混合继承是一种设计模式,主要的类使用单重继承,同时允许各个类继承一个或多个辅助类,每个辅助类都会添加几个简单的元素

缺点:

更复杂

名称冲突

重复继承。重复继承表示从多条路径上继承了同一个元素

程序更难编写

使用继承的规则

  • 不要过度使用
  • 子类和父类之间应该有关系。比如Potato类继承Fruit类,这就是错误的
  • 子类应是父类的扩展。在子类中,应确保只添加新的特性,不要删除、禁用或重新解释特性
  • 尽量继承抽象类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值