9.1 抽象类和抽象方法
抽象类–普通类和接口之间的中庸之道
abstract void f()
包含一个或者多个抽象方法的类必须被限定为抽象的。
从一个抽象类继承,并想创建新的类对象,必须覆盖基类的所以抽象方法。
9.2 接口
接口中方法只有 声明 方法名、参数列表、返回类型。没有具体实现。
即,
public void f();
interface 关键字。implements关键字,“接口只是它的外貌,现在要声明如何构工作”。
只提供形式,而不提供任何具体实现。
接口中的域隐式为static和final的。
接口中的方法是public的。
9.3 完全解耦
继承结构限制了方法只能在类和子类。
接口则放宽了限制。
策略模式
能够根据所传递参数对象的不同,而具有不同行为的方法被称不同行为的方法,被称为策略模式。策略就是传递进去的参数,包含要执行的代码。
适配器 接受你有的接口,产生你需要的接口–implements 提供的伪多重继承机制。
solution A
import java.util.*;
import static tools.Print.print;
class Processor{
public String name(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class Upcase extends Processor{
String process(Object input){
return ((String) input).toUpperCase();
}
}
class Downcase extends Processor{
String process (Object input){
return ((String) input).toLowerCase();
}
}
class Splitter extends Processor{
String process(Object input){
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);
}
}
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]
Filter和Processor类具有相同的元素,但不能将Filter用作Apply.process()方法。
问题在于 Apply.process()方法和Processor之间耦合过紧,已经超出了需要的程度,使得复用被禁止。
solution B
package Ch9A;
import java.util.*;
public abstract class StringProcessor implements Processor{
public String name(){
return getClass().getSimpleName();
}
public abstract String process(Object input);
public static String s = "If she weighs the same as duck, she's made of wood";
public static void main(String[] args){
Apply.process(new Upcase(),s);
Apply.process(new DownCase(),s);
Apply.process(new Splitter(),s);
}
}
class Splitter extends StringProcessor {
public String process(Object input) {
return Arrays.toString(((String)input).split(" "));
}
}
class DownCase extends StringProcessor{
public String process(Object input){
return ((String)input).toLowerCase();
}
}
class Upcase extends StringProcessor {
public String process(Object input){
return ((String)input).toUpperCase();
}
}
/*
Using Processor Upcase
IF SHE WEIGHS THE SAME AS DUCK, SHE'S MADE OF WOOD
Using Processor DownCase
if she weighs the same as duck, she's made of wood
Using Processor Splitter
[If, she, weighs, the, same, as, duck,, she's, made, of, wood]
*/
Apply提供一样的将处理方法和对象结合在一起的方法。
solutin A 是将Processor作为基类,通过子类继承达到作为借口的目的。
solutin B 是将Processor作为interface(抽象),提供方法,不提供实现。
让实现接口的类来完成方法。
solution C
package Ch9A;
import static tools.Print.print;
public interface Processor {
String name();
Object process(Object input);
}
public class Apply {
public static void process(Processor p,Object s){
print("Using Processor "+p.name());
print(p.process(s));
}
}
import Ch9.*;
public class FilterAdapter implements Processor {
Filter filter;
public FilterAdapter(Filter filter)
{
this.filter = filter;
}
public String name()
{
return filter.name();
}
public Waveform process(Object input)
{
return filter.process((Waveform)input);
}
}
Using Processor LowPass
waveform0
Using Processor HighPass
waveform0
Using Processor BandPass
waveform0
9.4 java多重继承
使用接口的核心原因:为了向上转型为多个基类。
第二个原因同抽象基类一样:防止客户端程序员创建该类的对象。
如果创建不带任何方法和成员变量的基类,那么就应该选择接口,而不是抽象类。
事实上,如果知道某事物一个成为一个基类,那么第一选择应该是使它成为应该接口。
9.5 通过组合来扩展接口
package Ch9;
interface Monster{
void menace();
}
interface DangerousMonster extends Monster{
void destory();
}
interface Lethal{
void kill();
}
class DragonZilla implements DangerousMonster,Monster{
public void menace(){}
public void destory(){}
}
// extends 多个仅适用于接口
interface Vampire extends DangerousMonster,Lethal{
void drinkBlood();
}
class VeryBadVampire implements Vampire{
public void menace(){}
public void destory(){}
public void kill(){}
public void drinkBlood(){}
}
public class HorrorShow {
static void u(Monster b){b.menace();}
static void v(DangerousMonster d){
d.menace();
d.destory();
}
static void w(Lethal l){
l.kill();
}
public static void main(String[] args) {
DangerousMonster barney = new DragonZilla();
u(barney);
v(barney);
Vampire vlad = new VeryBadVampire();
u(vlad);
v(vlad);
w(vlad);
}
}
9.5.1组合接口时名字冲突
在打算组合的不同接口中使用相同的方法名通常会造成代码可读性的混乱,要避免。
9.6 适配接口
9.7 接口中的域
放入接口中的任何于都是static和final,public的。
9.8 嵌套接口
???
9.9接口和工厂
没太明白工厂方法。
与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口某个实现的对象。可以将代码和接口完全分离。
package Ch9;
import jdk.internal.dynalink.linker.LinkerServices;
import static tools.Print.print;
interface Service{
void method1();
void method2();
}
/*interface ServiceFactory{
Service getService();
}*/
class Implementation1 implements Service{
Implementation1(){}
public void method1(){print("Implemtentaion1 method1");}
public void method2(){print("Implemtentaion1 method2");}
}
/*class Implementation1Factory implements ServiceFactory{
public Service getService(){
return new Implemtentaion1();
}
}*/
class Implementation2 implements Service{
Implementation2(){}
public void method1(){print("Implemtentaion2 method1");}
public void method2(){print("Implemtentaion2 method2");}
}
/*class Implementation2Factory implements ServiceFactory{
public Service getService(){
return new Implementation2();
}
}*/
public class Factories {
public static void serviceConsumer(Service fact){
//Service s =fact.getService();
fact.method1();
fact.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1());
//Implementations are completely interchangerable
serviceConsumer(new Implementation2());
}
}
Implemtentaion1 method1
Implemtentaion1 method2
Implemtentaion2 method1
Implemtentaion2 method2
package Ch9;
import static tools.Print.print;
interface Game{boolean move();}
interface GameFactory{Game getGame();}
class Cherkers implements Game{
private int moves = 0;
private static final int MOVES =3;
public boolean move(){
print("moves = "+moves);
return ++moves!=MOVES;
}
}
class CherkersFactory implements GameFactory{
public Game getGame(){
return new Cherkers();
}
}
class Chess implements Game{
private int moves = 0;
private static final int MOVES = 4;
public boolean move(){
print("Chess move "+moves);
return ++moves !=MOVES;
}
}
class ChessFactory implements GameFactory{
public Game getGame(){
return new Chess();
}
}
public class Games {
public static void playGame(GameFactory factory){
Game s = factory.getGame();
while(s.move());
}
public static void main(String[] args) {
playGame(new CherkersFactory());
playGame(new ChessFactory());
}
}
moves = 0
moves = 1
moves = 2
Chess move 0
Chess move 1
Chess move 2
Chess move 3