这章介绍了适配器设计模式和策略设计模式。
第九章 接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法。
1、抽象类和抽象方法
public abstract void f();
创建抽象类是希望通过这个通用接口操纵一系列类。如果一个类包含大于等于一个抽象方法,那么这个类就是抽象类,必须用abstract关键字来限定这个抽象类。
如果试图直接创建该抽象类的对象,编译器会报错。
如果抽象类的子类没有为基类的抽象方法提供定义,那么这个导出类依旧是抽象类。
抽象类也可以不包含任何抽象方法,单纯的用abstract限定类。(该类不能产生对象)
2、接口
interface这个关键字替代class关键字,产生了一个完全抽象的类。接口只提供形式,未提供任何具体实现。
接口被用了建立类与类之间的协议。接口也可以包含域,但是
这些域隐式的是static和final的。因此,其中定义的成员变量,是static&final的。
implenments关键字可以跟一组接口,extends关键字只能跟一个基类。
接口中的方法必须是public的,隐式的被声明public的,如果要显示声明,它们也必须被声明为public的。否则在继承的过程中,可访问权限被降低,这是java编译器所不允许的。
3、完全解耦
策略设计模式:创建一个能够根据传递参数对象不同而具有不同行为的方法。比如:
package interfaces.classprocessor;
import java.util.*;
import static net.mindview.util.Print.*;
class Processor {
public String name() {
return getClass().getSimpleName();
}
Object process(Object input) { return input; }
}
class Upcase extends Processor {
String process(Object input) { // Covariant return
return ((String)input).toUpperCase();
}
}
class Downcase extends Processor {
String process(Object input) {
return ((String)input).toLowerCase();
}
}
class Splitter extends Processor {
String process(Object input) {
// The split() argument divides a String into pieces:
return Arrays.toString(((String)input).split(" "));
}
}
public class Apply {
public static void process(Processor p, Object s) {
print("Using Processor " + p.name());
print(p.process(s));
}
public static String s =
"Disagreement with beliefs is by definition incorrect";
public static void main(String[] args) {
process(new Upcase(), s);
process(new Downcase(), s);
process(new Splitter(), s);
}
} /* Output:
Using Processor Upcase
DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT
Using Processor Downcase
disagreement with beliefs is by definition incorrect
Using Processor Splitter
[Disagreement, with, beliefs, is, by, definition, incorrect]
4、java中的多重继承
java没有任何与接口相关的存储,因此可以继承任意多个接口。\
使用接口的核心原因:为了能够向上转型为多个基本类型。顺带可以防止客户端程序员创建该类的对象。
5、通过继承扩展接口
extends只能用于单一类,但是接口继承时却可以引用多个接口,用逗号分开。
interface Interface1 extends Interface2,Interface3{}
接口无法用implements来实现别的接口,必须用extends。
应该尽量避免组合的多个接口中包含相同方法名,这样会造成代码可读性的混乱。
6、适配接口
类的构造器接受一个接口,将希望使用该类的类都实现该接口,这样可以类就可以作用于更多的类型。比如Scanner类,想使用该类的类型
和策略模式的不同:
方法可以作用于不同的类型。
而适配器模式是,将不同类型作为类构造器的参数传入,有点类已经固定了,等着别人用的时候向下转型成接口类的感觉。
7、接口中的域
接口中的域是static&final的,所以常量初始化值会用大写字母的风格。
package interfaces;
public interface Months {
int
JANUARY = 1, FEBRUARY = 2, MARCH = 3,
APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,
AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,
NOVEMBER = 11, DECEMBER = 12;
}
但是一般不这么做,在接口中定义常量,而是用enum关键字实现。
接口中定义的常量一定要初始化,不能出现空final,但是可以被非常量表达式初始化。
8、嵌套接口
嵌套在另一个接口中的接口自动是public的,而不能声明为private的.
当实现某个接口是,并不需要实现嵌套在其内部的任何借口,而且,private接口不能在定义它的类之外被实现。
9、接口与工厂
工厂设计模式:
在工厂对象上调用创建方法,该工厂对象将生成接口的某个实现对象。这样将代码与接口实现分离,这样使得我们可以透明的将某个实现替换成另一个实现。
import static net.mindview.util.Print.*;
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service getService();
}
class Implementation1 implements Service {
Implementation1() {} // Package access
public void method1() {print("Implementation1 method1");}
public void method2() {print("Implementation1 method2");}
}
class Implementation1Factory implements ServiceFactory {
public Service getService() {
return new Implementation1();
}
}
class Implementation2 implements Service {
Implementation2() {} // Package access
public void method1() {print("Implementation2 method1");}
public void method2() {print("Implementation2 method2");}
}
class Implementation2Factory implements ServiceFactory {
public Service getService() {
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact) {
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
// Implementations are completely interchangeable:
serviceConsumer(new Implementation2Factory());
}
} /* Output:
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
对消费者传递一个工厂1对象,产生工厂1的产品,调用产品1的方法。
对消费者传递一个工厂2对象,产生工厂2的产品,调用产品2的方法。