JAVA编程思想学习总结:第9章接口
2015-05-20 10:27
609 查看
(1)抽象和接口
Java提供一个叫做抽象方法的机制,这种方法是不完整的,仅有声明而没有方法体。在方法声明前加关键字abstract。包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的(在其定义前添加abstract关键字)。抽象类不允许直接创建新对象,必须通过通过继承抽象类后,并为所有抽象方法提供方法定义后,才能创建该导出类对象,如果不为所有抽象方法提供方法定义,这个导出类也必须定义为抽象类。
当然创建一个没有任何抽象方法的抽象类也是允许的,这样可以阻止产生这个类的任何对象。
接口关键字使得抽象的概念更向前迈进了一步,接口所有的方法只有定义,不提供任何具体的实现。接口中可以包含域,但是这些域隐式的是static和final的(这一效果在java SE5 以前用来实现enum类型)。接口中的方法陷式的是public的,且必须是public的。
利用接口可以实现多继承。这是程序中使用接口的核心原因:为了能够向上转型为多个基类型(以及由此而带来的灵活性)。第二个原因是防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口。
(2)策略模式和适配器设计模式
/* * P177 */ import java.util.Arrays; interface Processor{ String name(); Object process(Object input); } class Apply{ public static void process(Processor p, Object s){ System.out.println("Using Processor " + p.name()); System.out.println(p.process(s)); } } public abstract class StringProcessor implements Processor{ public String name(){ return getClass().getName(); } public abstract String process(Object input); public static String s="If she weighs the same as a 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 Upcase extends StringProcessor{ public String process(Object input){ return ((String)input).toUpperCase(); } } class Downcase extends StringProcessor{ public String process(Object input){ return ((String)input).toLowerCase(); } } class Splitter extends StringProcessor{ public String process(Object input){ return Arrays.toString(((String)input).split(" ")); } }输出结果:
Using Processor interfaceClass.Upcase
IF SHE WEIGHS THE SAME AS A DUCK, SHE'S MADE OF WOOD
Using Processor interfaceClass.Downcase
if she weighs the same as a duck, she's made of wood
Using Processor interfaceClass.Splitter
[If, she, weighs, the, same, as, a, duck,, she's, made, of, wood]
创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式。这类方法追念所要执行的算法中固定不变的部分,而策略包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。
但是,如果现在的情况是无法修改想要使用的类,可以考虑适配器设计模式。适配器中的代码将接受你所拥有的接口,并产生你所需要的接口。
/* * P178 */ class Waveform{ private static long counter; private final long id = counter++; public String toString(){return "Waveform " +id;} } class Filter{ public String name(){return getClass().getName();} public Waveform process(Waveform input){return input;} } 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);} } class LowPass extends Filter{ double cutoff; public LowPass(double cutoff){this.cutoff = cutoff;} public Waveform process(Waveform input){return input;} } class HighPass extends Filter{ double cutoff; public HighPass(double cutoff) {this.cutoff = cutoff;} public Waveform process(Waveform input){return input;} } class BandPass extends Filter{ double lowCutoff,highCutoff; public BandPass(double lowCut,double highCut){ lowCutoff=lowCut; highCutoff=highCut; } public Waveform process(Waveform input){return input;} } public class FilterProcessor { public static void main(String[] args){ Waveform w =new Waveform(); Apply.process(new FilterAdapter(new LowPass(1.0)), w); Apply.process(new FilterAdapter(new HighPass(2.0)), w); Apply.process(new FilterAdapter(new BandPass(3.0,4.0)), w); } }运行结果:
Using Processor interfaceClass.LowPass
Waveform 0
Using Processor interfaceClass.HighPass
Waveform 0
Using Processor interfaceClass.BandPass
Waveform 0
在这种使用适配器的方式中,FilterAdapter的构造器接受你所拥有的接口Filter,然后生成你所需要的Processor接口的对象。还需要注意到的是,在FilterAdapter类中用到了代理。
(3)适配接口
import java.nio.*; import java.util.*; /* * P182 */ public class RandomWords implements Readable{ private static Random rand = new Random(47); private static final char[] capitals = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); private static final char[] lowers="abcdefghijklmnopqrstuvwxyz".toCharArray(); private static final char[] vowels={'a','e','i','o','u'}; private int count; public RandomWords(int count){this.count = count;} public int read(CharBuffer cb){ if(count-- == 0) return -1; cb.append(capitals[rand.nextInt(capitals.length)]); for(int i = 0;i<4;i++){ cb.append(vowels[rand.nextInt(vowels.length)]); cb.append(lowers[rand.nextInt(lowers.length)]); } cb.append(" "); return 10; } public static void main(String[] args){ Scanner s = new Scanner(new RandomWords(10)); while(s.hasNext()) System.out.println(s.next()); } }Readable接口只要求实现read()方法,在read()内部,将输入内容添加到CharBuffer参数中。
import java.util.Random; import java.nio.*; import java.util.*; /* * P183 */ class RandomDoubles{ private static Random rand = new Random(47); public double next(){return rand.nextDouble();} public static void main(String[] args){ RandomDoubles rd = new RandomDoubles(); for(int i=0;i<7;i++){ System.out.println(rd.next()+" "); } } } public class AdaptedRandomDoubles extends RandomDoubles implements Readable{ private int count; public AdaptedRandomDoubles(int count){ this.count=count; } public int read(CharBuffer cb){ if(count-- ==0) return -1; String result = Double.toString(next())+" "; cb.append(result); return result.length(); } public static void main(String[] args){ Scanner s=new Scanner(new AdaptedRandomDoubles(7)); while(s.hasNextDouble()) System.out.println(s.nextDouble() +""); } }
以上两段代码再次分别采用了策略模式和适配器模式。
(4)接口嵌套
package interfaceClass; /* * P185-186 */ class A{//接口嵌套在类中 interface B{ void f(); } public class BImp implements B{ public void f(){} } private class Bimp2 implements B{//接口可以被实现为private public void f(){} } public interface C{ void f(); } class CImp implements C{ public void f(){} } private class CImp2 implements C{ public void f(){} } private interface D{//接口只有在类嵌套中才可以被定义为private void f(); } private class DImp1 implements D{ public void f(){} } public class DImp2 implements D{ //private嵌套类不仅可以被实现为private,还可以被实现为public,但DImp还是只能被其自身所用 //因此,实现private接口只是一种方式,它可以强制该接口中的方法定义不要添加任何类型信息(也就是说不允许向上转型) public void f(){} } public D getD(){return new DImp2();}//该方法的返回值只能交给有权使用它的对象 private D dRef; public void receiverD(D d){ dRef =d; dRef.f(); } } interface E{//接口嵌套在接口中 interface G{ void f(); } public interface H{ void f(); } void g(); //接口中嵌套的接口只能定义为public,和接口中定义的方法一样。 } public class NestingInterfaces { public class BImp implements A.B{ public void f(){} } class CImp implements A.C{ public void f(){} } //cannot implement a private interface except //within that interface's defining class: //! class DImp implements A.D{ //! public void f(){} //! } class EImp implements E{ public void g(){} } class EGimp implements E.G{ public void f(){} } class EImp2 implements E{ public void g(){} class EG implements E.G{ public void f(){} } } public static void main(String[] args){ A a =new A();//实现一个包含嵌套接口的类时时,并不需要实现嵌套在该类内部的任何接口 //Can't access A.D; //! A.D ad=a.getD(); //Doesn't return anything but A.D; //! A.DImp2 di2 = a.getD(); // Cannot access a member of the interface; //! a.getD().f(); // Only another A can do anything with gerD(); A a2=new A(); a2.receiverD(a.getD()); } }
(5)工厂方法
interface Service{ void method1(); void method2(); } interface ServiceFactory{ Service getService(); } class Implementation1 implements Service{ Implementation1(){} public void method1() {System.out.println("Implementation1 method1");} public void method2() {System.out.println("Implementation1 method2");} } class Implementation1Factory implements ServiceFactory{ public Service getService(){ return new Implementation1(); } } class Implementation2 implements Service{ Implementation2(){} public void method1(){System.out.println("Implementation2 method1");} public void method2(){System.out.println("Implementation2 method1");} } 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()); serviceConsumer(new Implementation2Factory()); } }
工厂方法设计模式与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现。
(6)策略模式与状态模式的异同
(转自http://www.blogjava.net/4cai/archive/2014/05/16/413717.html)相同之处:
1、添加新的状态或策略都很容易,而且不需要修改使用它们的Context对象。
2、它们都让你的代码符合OCP原则。在状态模式和策略模式中,Context对象对修改是关闭的,添加新的状态或策略,都不需要修改Context。
3、正如状态模式中的Context会有初始状态一样,策略模式同样有默认策略。
4、状态模式以不同的状态封装不同的行为,而策略模式以不同的策略封装不同的行为。
5、它们都依赖子类去实现相关行为。
不同之处:
1、策略模式封装了一组相关算法,它允许Client在运行时使用可互换的行为;状态模式帮助一个类在不同的状态显示不同的行为。
状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。
2、在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。
3、策略实现可以作为参数传递给使用它的对象,例如Collections.sort(),它的参数包含一个Comparator策略。另一方面,状态是Context对象自己的一部分,随着时间的推移,Context对象从一个状态转移到另一个状态。
虽然它们都符合OCP原则,策略模式也符合SRP原则(单一职责原则),因为每个策略都封装自己的算法,且不依赖其他策略。一个策略的改变,并不会导致其他策略的变化。
4、另一个理论上的不同:策略模式定义了对象“怎么做”的部分。例如,排序对象怎么对数据排序。状态模式定义了对象“是什么”和“什么时候做”的部分。例如,对象处于什么状态,什么时候处在某个特定的状态。
5、状态模式中很好的定义了状态转移的次序;而策略模式并无此需要:Client可以自由的选择任何策略。
6、一些常见的策略模式的例子是封装算法,例如排序算法,加密算法或者压缩算法。如果你看到你的代码需要使用不同类型的相关算法,那么考虑使用策略模式吧。而识别何时使用状态模式是很简单的:如果你需要管理状态和状态转移,但不想使用大量嵌套的条件语句,那么就是它了。
7、最后但最重要的一个不同之处是,策略的改变由Client完成;而状态的改变,由Context或状态自己。
相关文章推荐
- JAVA编程思想学习总结:第十章接口内部类
- JAVA编程思想学习总结:第21章第4节终结与协作
- JAVA编程思想学习总结:第八章——多态
- JAVA编程思想学习总结:第十一章持有对象
- JAVA编程思想学习总结:第十三章字符串
- JAVA编程思想学习总结:第十四章类型信息
- 【java编程思想--学习笔记(三)】访问控制-接口实现与类的访问权限
- JAVA编程思想学习总结:第五章——初始化与清理
- JAVA编程思想学习总结:第七章——复用类
- JAVA编程思想学习总结:第21章第1-2节基本的线程机制
- JAVA编程思想学习总结:第21章第3节共享受限资源
- Java编程思想:第9章 接口
- java编程思想学习笔记之第9章 抽象类
- Java编程思想学习笔记-第九章 接口
- Java编程思想——第六章 访问权限控制 学习总结
- Java编程思想-接口总结
- Java编程思想 一二章学习总结
- Java编程思想,读书笔记七(第9章 接口)
- Java编程思想 五六章学习总结
- Java编程思想 七八章学习总结