TJI读书笔记12-接口

body, td {
font-family: 微软雅黑;
font-size: 10pt;
}

接口和抽象类为我们提供了更强又有力的接口和实现分离的方法.

抽象类和抽象方法

抽象类的目的是为了给子类提供一个通用接口,通过这样一个通用的接口,可以操纵一系列的子类. 也就是说,只需要通过相同的接口调用就可以操作不用的实现. 这也就是所谓的接口和实现的分离.

抽象类简单来说就是包含抽象方法的类. 那么,要了解抽象类就得先了解抽象方法. abstract void f();像这样的由abstract修饰的方法叫做抽象方法. 抽象方法只有返回值类型和方法签名,没有方法体. 抽象类同样适用abstract修饰,并且抽象类不能实例化.

1.abstract class Instrument{2.3.    abstract public void paly(Note m);4.    private void test1(){5.        System.out.println("Instrument");6.    }7.}8.class Wind extends Instrument{9.    public void paly(Note m){10.        System.out.println("Wind play()");11.    }12.13.    public void test1(){14.        System.out.println("111");15.    }16.}17.18.public class Music {19.    public static void tune(Instrument i){20.        i.paly(Note.C_SHARP);21.    }22.    public static void main(String[] args) {23.        Wind flute = new Wind();24.        tune(flute);25.    }26.}

抽象类作为基类,对子类中需要改变的方法仅提供abstract方法,对于其他方法,可以正常提供方法体,算是一种介于接口和正常类之间的一种中庸的方案. 抽象类使类的抽象性明确起来了. 抽象类是很重要的重构工具,因为它可以容易的将公共方法沿着继承层次结构向上移动.(埃大爷说的好学院范儿…)

接口

如果一个抽象类中的方法都是抽象方法,那么它的作用就更抽象了. 这么一种纯粹的抽象类,它只提供一个类型的接口定义,没有任何实现. 那么这么一种抽象的令人发指的抽象类如果不给它定义成一个新的概念简直天理难容. 于是这种玩意儿就叫做接口. 它只提供一个类的接口定义于是就被粗暴的叫成了接口… 注意这个接口是java的一种类型机制,平时所说的类的接口是指类中暴露出的可以使用的方法. 可以说接口是用用来被建立类和类之间的协议. (有些语言会直接使用protocol完成这一功能)

interface不仅仅是一个纯粹的抽象类,它允许人们通过创建一个能够被向上转型的多种基类的类型. 除了这个,interface还有一个功能就是可以实现类似多继承的功能. 需要注意的几个点:

  • 接口中定义的方法,隐式添加 public static final

  • 接口中可以定义成员变量,默认都是static final的
  • 要让一个类实现一个接口需要使用implements关键字
  • 实现一个接口的类必须要实现这个接口中定义的所有方法.
  • 实现一个接口的类,可以定义自己的public方法. 也就是说实现一个interface的类对外提供的接口是所实现interface的子集.
1.interface Instrument2{2.    int Value = 5;3.    void paly(Note n);4.    void adjust();5.}6.7.public class Wind2 implements Instrument2{8.    public void paly(Note n ){9.        System.out.println(this+".play() "+n);10.    }11.    public void adjust(){12.        System.out.println(this+".adjust()");13.    }14.    public String toString(){15.        return "Wind";16.    }17.    public void foo1(){18.        System.out.println("hoho");19.    }20.21.    public static void main(String[] args) {22.        Wind2 wind = new Wind2();23.        wind.adjust();24.        wind.paly(Note.B_FLAT);25.        wind.foo1();26.        System.out.println(Instrument2.Value);27.    }28.}

完全解耦和策略模式

1.import java.util.Arrays;2.3.class Processor{4.    public String name(){5.        return getClass().getSimpleName();6.    }7.    Object process(Object input){8.        return input;9.    }10.}11.12.class UpCase extends Processor{13.    String process(Object input){14.        return ((String)input).toUpperCase();15.    }16.}17.18.class LowerCase extends Processor{19.    String process(Object input){20.        return ((String)input).toLowerCase();21.    }22.}23.24.class Splitter extends Processor{25.    String process(Object input){26.        return Arrays.toString(((String)input).split(" "));27.    }28.}29.30.public class Apply {31.    public static void process(Processor p,Object s){32.        System.out.println("using Processor "+p.name());33.        System.out.println(p.process(s));34.    }35.    public static String s = "hello world";36.    public static void main(String[] args) {37.        Apply.process(new UpCase(), s);38.        Apply.process(new LowerCase(), s);39.        Apply.process(new Splitter(), s);40.    }41.}

上面是一个经典的策略模式,同一个方法,根据入参不同会有不同的行为. 所谓见人说人话,见鬼说鬼话. 注意实现方式,本质其实就是多态. 策略就是传入的参数的对象.它包含所要执行的代码.

但是看下面这个例子

1.public class Waveform {2.    private static long counter;3.    private final long id = counter++;4.    public String toString(){5.        return "Waveform "+id;6.    }7.}8.//=========================================================9.public class Filter {10.    public String name(){11.        return getClass().getSimpleName();12.    }13.    public Waveform process(Waveform input){14.        return input;15.    }16.}17.//=========================================================18.public class LowPass extends Filter{19.    double cutoff;20.21.    public LowPass(double cutoff){22.        this.cutoff=cutoff;23.    }24.    public Waveform process(Waveform input){25.        return input;26.    }27.}28.//=========================================================29.public class HighPass extends Filter{30.    double cutoff;31.32.    public HighPass(double cutoff) {33.        this.cutoff = cutoff;34.    }35.    public Waveform process(Waveform input) {36.        return input;37.    }38.}39.//=========================================================40.public class BandPass extends Filter{41.    double lowCutoff,HighCutoff;42.43.    public BandPass(double lowCutoff,double HighCutoff){44.        this.HighCutoff=HighCutoff;45.        this.lowCutoff=lowCutoff;46.    }47.    public Waveform process(Waveform input){48.        return input;49.    }50.}51.

上面这段代码就会有个问题,Filter和Processor虽然有相同的接口元素,但是他并非继承自Processor. 因为Filter的创建者可能并不知道你想将其用作processor. 这样就不能通过Apply.process()来调用了. 虽然也有办法可以正常运行,但是processor和Apply.process()之间的耦合太紧. 想复用Apply.process()的时候就出现问题. 所以有个办法就是把processor抽象为一个接口,然后处理不同问题的时候,再去实现这个接口.

1.public interface Processor{2.    public String name();3.    public Object process(Object input);4.}5.//=========================================================6.import java.util.Arrays;7.public abstract class StringProcessor implements Processor {8.    public String name() {9.        return getClass().getSimpleName();10.    }11.12.    public abstract String process(Object input);13.14.    public static String s = "hello world";15.16.    public static void main(String[] args) {17.        Apply.process(new UpCase(), s);18.        Apply.process(new LowerCase(), s);19.        Apply.process(new Splitter(), s);20.    }21.}22.23.class UpCase extends StringProcessor {24.25.    public String process(Object input) {26.        return ((String) input).toUpperCase();27.    }28.29.}30.31.class LowerCase extends StringProcessor {32.    public String process(Object input) {33.        return ((String) input).toLowerCase();34.    }35.}36.37.class Splitter extends StringProcessor {38.    public String process(Object input) {39.        return Arrays.toString(((String) input).split(" "));40.    }41.}42.//=========================================================43.public abstract class FilterProcessor implements Processor{44.45.    @Override46.    public String name() {47.48.        return getClass().getSimpleName();49.    }50.    @Override51.    abstract public Waveform process(Object input);52.53.    public static Waveform w = new Waveform();54.    public static void main(String[] args) {55.        Apply.process(new HighPass(1222.222), w);56.        Apply.process(new LowPass(1222.222), w);57.        Apply.process(new BandPass(1222.222,3333.3333), w);58.    }59.}60.//=========================================================61.public class HighPass extends FilterProcessor{62.63.    double cutoff;64.65.    public HighPass(double cutoff) {66.        this.cutoff = cutoff;67.    }68.    @Override69.    public Waveform process(Object input) {70.        return (Waveform)input;71.    }72.}73.class LowPass extends FilterProcessor{74.75.    double cutoff;76.77.    public LowPass(double cutoff){78.        this.cutoff=cutoff;79.    }80.    @Override81.    public Waveform process(Object input){82.        return (Waveform)input;83.    }84.}85.class BandPass extends FilterProcessor{86.    double lowCutoff,HighCutoff;87.88.    public BandPass(double lowCutoff,double HighCutoff){89.        this.HighCutoff=HighCutoff;90.        this.lowCutoff=lowCutoff;91.    }92.    @Override93.    public Waveform process(Object input) {     94.        return (Waveform)input;95.    }96.}

如果有时候碰到了一些你想使用,但是又不能修改的类. 那么就可以使用一种新的模式,适配器模式. 适配器中的代码将接受你所拥有的接口,并且产生你需要的接口.

1.class FilterAdapter implements Processor{2.    Filter filter;3.    public FilterAdapter(Filter filter){4.        this.filter= filter;5.    }6.    @Override7.    public String name(){8.        return filter.name();9.    }10.    @Override11.    public Waveform process(Object input){12.        return filter.process((Waveform)input);13.    }14.}15.16.public class NewFilterProcessor{17.    public static void main(String[] args) {18.        Waveform w = new Waveform();19.        Apply.process(new FilterAdapter(new LowPass(1.0)), w);20.        Apply.process(new FilterAdapter(new HighPass(2.0)), w);21.        Apply.process(new FilterAdapter(new BandPass(1.0,2.0)), w);}22.}


(这个生成UML的插件貌似有bug,还是我对UML的理解有bug,总感觉哪里不对劲…)

像这个样子,FilterAdapter接受processor的接口,然后生成我们需要的process()接口.这是应该是适配器模式的重要作用之一.
还有一个用途, 比如ContainerAdapter这个类,实现了ContainerListener接口,但是所有方法都是空并未提供实际的方法代码.那这种Adapter的作用很巧妙,这样我们只需要继承这个类,就等于实现了这个接口,于此同时可以只实现自己感兴趣的方法. 而不像直接实现接口那样即使只对其中部分方法感兴趣也要实现所有的方法.

interface从具体实现中解耦,使得接口可以应用于多种不同的具体实现,因此代码就更具有可复用性.

java中的多继承
C++中允许多重继承,即一个子类可以有多个基类.这样会造成一些混淆. java中禁止了这种方式的多重继承. java中的类,一个子类只能有一个基类,但是是可以实现多个接口的.

接口间的继承关系

接口之间是可以存在继承关系的,通过继承,可以扩展一个interface的所拥有的接口.

1.interface Monster {2.    void menace();3.}4.5.interface DanderousMonster extends Monster {6.    void destroy();7.}8.9.interface Lethal {10.    void kill();11.}12.13.class DragonZilla implements DanderousMonster {14.15.    @Override16.    public void menace() {17.        // TODO Auto-generated method stub18.19.    }20.21.    @Override22.    public void destroy() {23.        // TODO Auto-generated method stub24.25.    }26.27.}28.29.interface Vampire extends DanderousMonster, Lethal {30.    void drinkBlood();31.}32.33.class VeryBadVampire implements Vampire {34.35.    @Override36.    public void destroy() {37.        // TODO Auto-generated method stub38.39.    }40.41.    @Override42.    public void menace() {43.        // TODO Auto-generated method stub44.45.    }46.47.    @Override48.    public void kill() {49.        // TODO Auto-generated method stub50.51.    }52.53.    @Override54.    public void drinkBlood() {55.        // TODO Auto-generated method stub56.57.    }58.59.}

组合接口时的名字冲突问题
这是一个可能会遇到的问题, 不同的接口中的两个方法,方法名一样但是,签名或者返回类型不同. 那这种时候会发生什么事情呢?
看一段让人心碎的代码

1.interface I1{2.    public void f();3.}4.interface I2{5.    public int f(int i);6.}7.interface I3{8.    public int f();9.}10.class C{11.    public int f(){12.        return 2;13.    }14.}15.16.17.class C2 implements I1,I2{18.19.    @Override20.    public int f(int i) {21.        return 0;22.    }23.24.    @Override25.    public void f() {26.    }27.}28.29.class C3 extends C implements I2{30.31.    @Override32.    public int f(int i) {33.        return 0;34.    }35.36.}37.38.class C4 extends C implements I3{39.    @Override40.    public int f(){41.        return 3;42.    }43.}44.45.//The return types are incompatible for the inherited methods I1.f(), C.f()46.class C5 extends C implements I1{47.48.}

其实从最简单的角度去理解,interface实现,类继承,反正无论多少东西混到一起,最终的作用效果就是,构建一个类的接口(方法).也就是说所有的方法最终都是要进到一个类中去 所以,方法名相同的时候,可不可以的衡量标准其实就是方法能不能重载.

但是,组合不同接口的时候,方法名相同可能会造成代码的可读性下降. 最好还是不要这么搞.

工厂模式

工厂方法模式与直接调用构造器不同. 我们在工厂对象上调用创建的方法. 这样做的好处是,代码完全与接口实现分离. 像下面这段代码中. 要创建不同的对象,只需要调用同一个方法Factories.serviceCustomer()方法即可.
工厂模式在创建框架的过程中使用的最多.

1.interface Service{2.    void method1();3.    void method2();4.}5.interface ServiceFactory{6.    Service getService();7.}8.9.class Implementation1 implements Service{10.11.    @Override12.    public void method1() {13.        System.out.println("111:method1");14.    }15.16.    @Override17.    public void method2() {18.        System.out.println("111:method2");19.    }20.}21.22.class Implementation2 implements Service{23.24.    @Override25.    public void method1() {26.        System.out.println("222:method1");27.    }28.29.    @Override30.    public void method2() {31.        System.out.println("222:method2");32.    }33.}34.35.class Implementation1Factory implements ServiceFactory{36.37.    @Override38.    public Service getService() {39.        return new Implementation1();40.    }41.42.}43.44.class Implementation2Factory implements ServiceFactory{45.46.    @Override47.    public Service getService() {48.        return new Implementation2();49.    }50.51.}52.53.public class Factories {54.    public static void serviceCustomer(ServiceFactory fact){55.        Service s = fact.getService();56.        s.method1();57.        s.method2();58.    }59.60.    public static void main(String[] args) {61.        Factories.serviceCustomer(new Implementation1Factory());62.        Factories.serviceCustomer(new Implementation2Factory());63.    }64.}/*out65.111:method166.111:method267.222:method168.222:method269.*/

乱七八糟不知道怎么归类的知识点

接口中的域
接口中是可以声明成员变量的,接口中的所有变量默认就是static fianl的. 所以在1.5之前,使用interface来构建枚举类型是个不错的选择.
接口中变量的域不能是空的final类型. 但是可以通过非常量表达式赋值.

接口的嵌套
接口是可以相互嵌套的. 但是实在是没看懂. 以后再说吧.

时间: 2024-10-06 00:14:32

TJI读书笔记12-接口的相关文章

TJI读书笔记15-持有对象

body, td { font-family: 微软雅黑; font-size: 10pt; } TJI读书笔记15-持有对象 总览 类型安全和泛型 Collection接口 添加元素 List 迭代器 LinkedList 栈 Set Map Queue Collection和Iterator Foreach与迭代器 总结 总览 It's a fairly simple program that only has a fixed quantity of objects with known l

TJI读书笔记16-异常处理

TJI读书笔记16-异常处理 概念 基本异常情形 异常的捕获 自定义异常 异常说明 捕获所有异常 栈轨迹 重新抛出异常 Java标准异常 使用finally 异常的限制 构造器 异常的匹配 其他乱七八糟 概念 在早期没有专门的异常处理机制的时候,比如C语言,会通过一些约定俗成的东西来处理异常. 比如让程序返回某个特殊的值或者设置某个标记. 然后对返回值进行检查以判断程序是否出错. 还记得以前C语言的时候,return 0和return -1对异常处理的实现可以追溯到BASIC中的on error

TJI读书笔记11-多态

body, td { font-family: 微软雅黑; font-size: 10pt; } TJI读书笔记11-多态 再说说向上转型 多态的原理 构造器和多态 协变返回类型 使用继承进行设计 多态是数据抽象和继承之后的第三种基本特征. 一句话说,多态分离了做什么和怎么做(再次对埃大爷佩服的五体投地,简直精辟啊). 是从另外一个角度将接口和实现分离开来. 封装通过合并特征和行为来创建新的数据对象,通过私有化隐藏细节,把接口和实现分离开来. 多态则是消除类型之间的耦合关系. 继承是允许将对象视

TJI读书笔记09-访问控制权限

body, td { font-family: 微软雅黑; font-size: 10pt; } TJI读书笔记09-访问控制权限 包,package和import 权限修饰符 接口和实现 类的访问权限控制 首先问一个问题,为什么要有访问控制权限? 安全,这当然是一个很重要的原因. 让类库的使用者只能接触他做需要接触的东西. 另外一方面,当我们去重构和修改代码的时候,如何不影响其他的代码和功能?权限访问控制是可以很好的将"变动的事物"和"不变的事物"区分开来.比如一

TJI读书笔记10-复用类

body, td { font-family: 微软雅黑; font-size: 10pt; } TJI读书笔记10-复用类 组合语法 继承语法 代理 final关键字 final的数据 final的参数 final的方法 final的类 初始化和类的加载 乱七八糟不知道怎么归类的知识点 代码复用是java众多牛逼哄哄的功能之一(好像OOP语言都可以呢-),代码复用的理想状态是,使用类但是又不破坏现有代码. 当然住了复制粘贴以外还有其他的方法. 一个叫组合,一个叫继承. 组合语法 其实刚开始我非

TJI读书笔记07-初始化

body, td { font-family: 微软雅黑; font-size: 10pt; } TJI读书笔记07-初始化 成员初始化 构造方法初始化 初始化块 初始化的顺序 成员初始化 java尽量去保证每个变量在使用前都会得到初始化. 对于方法局部变量,java不会自动初始化他们,如果没有显式的初始化,编译器会报错. 对于类的数据成员,java会自动初始化成一个"空""的值.简单来说,这个空的值对于基本数据类型就是,0,false,和空格. 对于引用类型就是null.

大话设计模式读书笔记--12.状态模式

定义 状态模式定义: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来改变了其类 消除庞大的条件分支,将特定状态的行为放入一个对象中 生活中:开灯和关灯是两个状态 模式结构 Context: 上下文环境,维护一个状态实例,定义当前的状态 State: 抽象状态类,定义一个接口,封装与Context的一个特定状态相关的行为 ConcreteState:具体状态.实现Context的一个特定状态相关的行为 代码实现 场景: 12店之前是休闲状态, 之后是忙碌状态 点击下载代码 特点及使用场

Programming in Scala (Second Edition) 读书笔记12 Trais

1.什么是Trait ? Traits are a fundamental unit of code reuse in Scala. A trait encapsulatesmethod and field definitions, which can then be reused by mixing them intoclasses. Unlike class inheritance, in which each class must inherit from justone supercla

<C和指针---读书笔记12>

Struct. 有时候我们希望把归属于一类的信息放在一起,便于查看.如一个员工的姓名.编号.工资.出勤.它又 字符串.int.float.数组等 构成.C提供了struct,使他们聚合在一起,便于我们访问. 结构定义 很显然,结构也是一个变量,它有自己的变量名,类型是struct;除此之外,我们还要说明 它由什么构成. (1)  struct  { member list }  x; 这个跟 int x一样,声明一个int型变量x.此处,声明一个 由member_list 组合构成的struct