本文参考:《修炼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