您的位置:首页 > 编程语言 > Java开发

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或状态自己。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: