effective java(18) 之接口优于抽象类

effective java 之接口优于抽象类


1、Java程序设计语言提供了两种机制,可以用来定义允许多个实现的类型:接口和抽象类。
2、两种机制之间最明显的区别在:
① 抽象类允许包含某个方法的实现,而接口则不允许。
②为了实现由抽象类定义的类型,类必须成为抽象类的一个子类。Java只允许单继承,所以,抽象类作为类型定义受到了极大限制。


3、现在的类可以很容易的被更新,以实现新的接口。 
如果这些方法尚不存在,你需要做的就只是增加必要的方法,然后在类的声明中增加一个implement子句。
如果你希望实现两个类扩展同一个类的抽象类,就必须把抽象类放到极高的一个层次中,以便这两个类的一个祖先成为它的子类。遗憾的是,这样做会间接的伤害到类层次,迫使这个公共祖先的所有的后代类都扩展了这个新的抽象类,无论它对于这些后代类是否合适。


4、接口定义mixin(混合类型)的理想选择。
不严格的来讲,mixin是指这样的类型:类除了实现它的“基本类型”之外,还可以实现这个mixin类型,以表明它提供了某些可选择的行为。它允许任选的功能可以被混合到类型的主要功能中。抽象类不能够被定义为mixin,同样也是因为它们不能被更新到现有的类:类不可能有一个以上的父类。


5、接口允许我们构造非层次结构的类型框架。
类型层次对于组织某些事物是非常合适的。但是其他有些事物并不能被整齐地组织成一个严格的层次结构。

public interface Singer{
 AudioClip sing(Song s);
}
public interface Songwriter{
 Song compose(boolean hit);
}
public interface SingerSongwriter extends Singer, Songwriter{
 AudioClip strum();
 void actSensitive();
}


你并不是总是需要这种灵活性,但是一旦你这样做了,接口可就成为了救世主,能帮助你解决大问题。另外一种做法是编写一个臃肿的类层次,对于每一种要被支持的属性组合,都包含一个单独的类。如果在整个类型系统中有n个属性,那么必须支持2^n种可能的组合。这种现象被称为“组合爆炸”。类层次的臃肿也导致类的臃肿,这些类也包含许多方法,并且这些方法只是在参数的类型上有所不同而已,因为类层次中没有任何类型体现公共的行为特征。


虽然接口不允许包含方法的实现,但是接口来定义类型并不妨碍你为程序员提供实现上的帮助。通过你导出的每个重要接口都提供一个抽象的骨架实现类(skeletal implementation)。把接口和抽象类的有点结合起来。接口的作用仍然是定义类型,但是骨架实现类接管了所有与接口实现相关的工作。


6、接口可以使得类的增强变得安全。
这一点主要说的是第16条(复合优于继承)中的“包装类”。


7、 骨架类
众所周知,java 8之前接口是不可以有方法体的,这就是抽象类相对于接口的优势,为了将抽象类和接口的优势整合起来,“骨架类”就诞生了,骨架类的做法是用一个抽象类来实现一个接口,在抽象类中为接口的某些方法提供实现。
骨架类的实现的一般步骤是,找出接口中的基本方法,在抽象类中声明为抽象方法,然后用这些基本方法来实现其他方法,所谓基本方法,就是通过将这些方法组合或是变换,可以实现其他的方法。
编写骨架实现类相对比较简单,只是有点单调乏味。首先,必须认真研究接口,并确定哪些方法时最为基本的,其他方法则可以根据它们来实现。这些方法将成为骨架实现类中的抽象方法。然后,必须为接口中的所有其他的方法提供具体实现。

8、架类的例子
假设有一个接口,它可以实现一组对象的求和:
	public interface Summation<T> {
		// 实现两个对象的相加
		T towEleAdd(T obj01, T obj02);


		// 实现List求和
		T listEleSum(List<T> list);


		// 实现数组求和
		T arrayEleSum(T[] array);
	}
实现他的“骨架”:
	public abstract class AbstractSummation<T> implements Summation<T> {

		@Override
		public abstract T towEleAdd(T obj01, T obj02);

		@Override
		public T listEleSum(List<T> list) {
			T firstEle = null;
			for (T t : list) {


				if (firstEle == null) {
					firstEle = t;
					continue;
				}


				firstEle = towEleAdd(firstEle, t);
			}
			return firstEle;
		}


		@Override
		public T arrayEleSum(T[] array) {
			T firstEle = null;
			for (T t : array) {


				if (firstEle == null) {
					firstEle = t;
					continue;
				}


				firstEle = towEleAdd(firstEle, t);
			}
			return firstEle;
		}
	}

继承这个骨架类就只用实现towEleAdd方法,就可以完成一组对象的求和工作了。
骨架实现类时为了继承的目的而设计的。

9、抽象类的优点
结合接口实现骨架实现(一般被称为AbstractInterface Interface表示接口)
比如:AbstratMap、AbstartList等等。
什么是骨架实现,如何实现
简单来讲,就是抽象类继承接口,不实现基本类型的接口方法,实现需要不实现基本类型接口的方法很好理解。 就是继承接口,然后再将无需实现的方法设为abstract,继续传递给子类实现。



参考资料
作者:想飞的僵尸

來源:简书


每天努力一点,每天都在进步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

powerfuler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值