Thinking in Java 4th chap9笔记-接口(二)
该接口的实现和向该方法传递的对象则取决于方法的使用者。因此接口的一种常见用法是策略设计模式。此时你编写一个执行某些操作的方法,而该方法将接受一个同样是你指定的接口,你主要就是要声明,“你可以用任何你想要的对象来调用我的方法,只要你的对象遵循我的接口”。这使你的方法更加灵活,通用并更具复用性。如Scanner的构造器参数Readable接口,通过这种方式,Scanner可以作用于更多的类型,只要你创建一个新类,并且让它成为Readable即可。
假设你有一个还未实现Readable接口的类B,怎么样才能让Scanner作用于它呢?-使用适配器模式,A extends B implements Readable接口即可。即被适配的类A可以通过继承B和实现Readable的类实现。因此,通过使用interface关键字提供的伪多重继承机制,我们可以生成既是B又是Readable接口的新类A.
这种方式,我们可以在任何现有类之上添加新的接口,所以这意味着让方法接受接口类型,如{@link Scanner};是一种让任何类都可以对该方法进行适配的方式。这是使用接口而不是类的强大之处。
7.接口中的域:
因为你放入接口中的任何域都自动是static和final的,所以接口就成为了一种很便捷的用来创建常量组的工具。在Java SE5之前,这是产生于C/C++的enum(枚举类型)具有相同效果的类的唯一途径。有了Java SE5,你就可以使用更加强大而且灵活的enum关键字,因此用接口群组常量已经显得没什么意义了。
1.初始化接口中定义的域
1.在接口中定义的域不能是空final,但是可以被非常量表达式初始化。因为域是static的,所以它们就可以在类第一次被加载时初始化。这发生在任何域首次被访问时。
注:域不是接口的一部分,它们的值被存储在该接口的静态存储区域内。
8.嵌套接口
1.接口可以嵌套在类中或其他接口中。这揭示了许多非常有趣的特性。
注:嵌套的private接口,实现一个private接口只是一个形式,它可以强制该接口中的方法定义不要添加任何类型信息,也就是说,不允许向上转型。个人理解是因为private接口,所以在外面调用中肯定不能被转型为定义的private接口类型,因为不可见。
getD方法使我们陷入了一个进退两难的境地,这个问题与private接口有关:它是一个返回private接口引用的public方法。你对这个方法的返回值能做些什么呢?在main中,我们可以看到,数次尝试使用返回值的行为都失败了。只有一种方式可以成功,那就是将返回值交给有权使用它的对象。在本例中,是另一个A通过receiveD来实现的。
同样,接口之间也可以彼此嵌套。然而,作用于接口中的各种规则,特别是所有的接口元素,都必须是public的,因此嵌套在 另一个接口中的接口自动就是public的,而不能声明为private的。
注:当要实现某个接口时,并不需要实现嵌套在其内部的任何接口,而且private接口不能在定义它之外的类实现。
9.接口与工厂
1.接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明的将某个实现替换为另一个实现。
1.如果不是用工厂方法,你的代码就必须在某处指定将要创建的Service确切类型,以便调用合适的构造器。为什么我们想要添加这种额外级别的间接性呢?一个常见的原因是想要创建框架:假设你正在创建一个对弈游戏系统,例如,在相同的棋盘上下国际象棋和西洋跳棋,如果Games类,处理逻辑,表示一段复杂的代码,那么这种方式允许你在不同类型的游戏中复用这段代码{@link Games}
2.下一章我们将会看到另一种更加优雅的工厂实现方式,那就是使用匿名内部类。
10.总结:
确定接口是理想选择,因而应该总是选择接口而不是具体的类。这其实是一种诱惑。当然,对于创建类,几乎在任何时刻,都可以替代为创建一个接口和一个工厂。许多人都掉进了这种诱惑的陷阱,只要有功能就去创建接口和工厂。这种逻辑看起来好像是因为需要使用不同的具体实现,因此总是应该添加这种抽象性。这实际上已经变成了一种草率的设计优化。
任何抽象性都应该是应真正的需求产生的。当必须时,你应该重构接口而不是到处添加额外级别的间接性,并由此带来额外的复杂性。这种额外的复杂性非常显著,如果你让某人去处理这种复杂性,只是因为你意识到由于以防万一而添加了新接口,而没有其他更具有说服力的原因,那么好吧,如果我碰上了这种事情,那么就会质疑此人所做的所有设计了。
恰当的原则应该是优先选择类而不是接口,从来开始,如果接口的必须性变得非常明确,那么就进行重构。接口是一种重要的工具,但是它们容易被滥用。
11.部分
源码:
package com.book.chap9.Interface;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.Random;
import java.util.Scanner;
/**
*
*使用interface的伪多重继承机制,可以让一个现有类{@link RandomDoubles}适配成为一个Scanner作用的对象
*
*
*这种方式,我们可以在任何现有类之上添加新的接口,所以这意味着让方法接受接口类型,如{@link Scanner}
*是一种让任何类都可以对该方法进行适配的方式。这是使用接口而不是类的强大之处。
*
*
*@author landon
*@version 1.0.0 2012-5-13 下午4:59:44
*@since JDK 1.6.0_30
*
*/
public class AdaptedRandomDoubles extends RandomDoubles implements Readable
{
private int count;
public AdaptedRandomDoubles(int count)
{
this.count = count;
}
@Override
public int read(CharBuffer cb) throws IOException
{
if(count-- == 0)
{
return -1;
}
String result = Double.toString(next()) + " ";
cb.append(result);
return cb.