本文参考:《修炼Java开发技术:在架构中体验设计模式和算法之美 于广编著》。
适配器模式是指将一个接口转换成客户希望的另一个接口,该模式使得原本不兼容的类可以一起工作。
适配器模式分为如下两类:
1、类的适配器模式。
2、对象的适配器,采用对象组合方式实现。
下面使用例子说明两类:
例如:现在在工作中有一个能说汉语和英语的岗位,而一个面试者只会说汉语,我们的任务就是将这个人适配到这个岗位中。
1、类的适配器模式:
package org.dyb.design.adapter;
public interface Job {
public void speakChinese();
public void speakEnglish();
}
package org.dyb.design.adapter;
public class Person {
public void speakChinese(){
System.out.println("speak chinese");
}
}
package org.dyb.design.adapter;
public class Adapter extends Person implements Job {
@Override
public void speakEnglish() {
System.out.println("speak English");
}
}
测试:
package org.dyb.design.adapter;
import org.junit.Test;
public class TestAdapter {
@Test
public void test(){
Job j = new Adapter();
j.speakChinese();
j.speakEnglish();
}
}
结果:
speak chinese
speak English
2、对象的适配器模式
只需要修改adapter适配器实现方法。
package org.dyb.design.adapter;
public class Adapter implements Job {
private Person person = null;
public Adapter(Person person){
this.person = person;
}
@Override
public void speakEnglish() {
System.out.println("speak English");
}
@Override
public void speakChinese() {
person.speakChinese();
}
}
测试:
package org.dyb.design.adapter;
import org.junit.Test;
public class TestAdapter {
@Test
public void test(){
Person p = new Person();
Job j = new Adapter(p);
j.speakChinese();
j.speakEnglish();
}
}
结果:
speak chinese
speak English
Java流接口和装饰模式的关系
Java程序中,inputstream抽象类中有很多子类,FileInputStream、ObjectInputStream、StringBufferInputStream、ByteArrayInputStream、PipedInputStream等是可以被装饰器装饰的对象。
FilterInputStream相当于装饰模式中的Decorator,而它的子类DataInputStream、BufferedInputStream、LineNumberInputStream、PushbackInputStream就相当于装饰模式中的ConcreteDecorator。
举例:
对英文进行加密,a->c y->a z->b
package decorator.demo;
import java.io.IOException;
import java.io.OutputStream;
public class EncryptOutputStream extends OutputStream {
private OutputStream os = null;
public EncryptOutputStream(OutputStream os) {
this.os = os;
}
@Override
public void write(int a) throws IOException {
a += 2;
if (a >= (97 + 26)) {
a -= 26;
}
this.os.write(a);
}
}
package decorator.demo;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.Test;
public class TestDecorator {
@Test
public void test() throws IOException {
DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(new EncryptOutputStream(
new FileOutputStream("mytest.txt"))));
dout.write("abcdxyz".getBytes());
dout.close();
}
}
打开mytest.txt
cdefzab
如果把EncryptOutputStream和bufferedOutputStream位置调换,这样就不行。因为EncryptOutputStream继承的不是装饰类
下面是最合理的解决方案:
让我们的装饰器集成装饰器的父类,就是FilterOutputStream类,然后使用父类提供的功能来协助完成想要装饰的功能。
package decorator.demo;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class EncryptOutputStream2 extends FilterOutputStream {
public EncryptOutputStream2(OutputStream os) {
super(os);
}
@Override
public void write(int a) throws IOException {
a += 2;
if (a >= (97 + 26)) {
a -= 26;
}
super.write(a);
}
}
运行test2
package decorator.demo;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.Test;
public class TestDecorator {
@Test
public void test() throws IOException {
DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(new EncryptOutputStream(
new FileOutputStream("mytest.txt"))));
dout.write("abcdxyz".getBytes());
dout.close();
}
@Test
public void test2() throws IOException{
DataOutputStream dout = new DataOutputStream(new EncryptOutputStream2 (new BufferedOutputStream(
new FileOutputStream("mytest.txt"))));
dout.write("abcdxyz".getBytes());
dout.close();
}
}
结果:cdefzab