IO流中的设计模式
一、装饰器模式
装饰器(Decorator)定义
在不必改变原类情况下,动态的扩展一个对象的功能,他是通过创建一个包装对象,也就是装饰来包装真实的对象
(方式)继承来扩展功能:java中的继承单继承
1、装饰器特点
Component:为统一接口,也是装饰类和被装饰类的基本类型。
ConcreteComponent:为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类
Decorator:是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。
ConcreteDecorator:是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent
注意:装饰器类可以有很多的变化
1、被装饰器的统一的接口,可以是一个接口,也可以是抽象父类
2、装饰器类Decorator可以不需要
2、代码示例
a、首先,先创建一个统一的接口,也是装饰类和被装饰类的基本类型
/**
* Component;
* 统一接口,也是装饰类和被装饰类的基本类型
*/
public interface Component {
void method();
}
b、创建一个装饰,实现接口
/**
* Decorator
* 是装饰类
* 实现了Component接口
*/
public abstract class Decorator implements Component {
//内部维护一个ConcreteComponent实例
protected Component component ;
//通过构造函数实例化ConcreComponent实例
public Decorator(Component component) {
this.component = component;
}
//Component接口提供的方法
@Override
public void method() {
component .method() ;
}
}
c、创建具体实现类
public class ConcreteComponent implements Component {
@Override
public void method() {
System.out.println(" 原来的方法 ");
}
}
/**
* 具体装饰器类A
* 继承自装饰器类
*/
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void methodA(){
System.out.println("装饰器A扩展的功能");
}
@Override
public void method(){
System.out.println("针对该方法添加一层A包装");
super .method() ;
System .out.println("A包装结束");
}
}
/**
* 具体装饰器类B
* 继承自装饰器类
*/
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
public void methodB(){
System.out.println("装饰器B扩展的功能");
}
@Override
public void method() {
System.out.println("针对该方法添加一层B包装");
super.method();
System.out.println("B包装结束");
}
}
三个具体实现类都继承装饰类,拓展原来的功能
d、TestDome
public static void main(String[] args) {
Component component =new ConcreteComponent() ;//原来的对象
component .method() ;//原来的方法
System.out.println("------------------------");
ConcreteDecoratorA concreteDecoratorA =new ConcreteDecoratorA(component );//装饰成A
concreteDecoratorA .method() ;
concreteDecoratorA .methodA() ;//装饰成A以后新增的方法
System.out.println("-------------------------");
ConcreteDecoratorB concreteDecoratorB=new ConcreteDecoratorB(component );//装饰成B
concreteDecoratorB .method() ;
concreteDecoratorB .methodB() ;
System.out.println("-------------------------");
concreteDecoratorB =new ConcreteDecoratorB(concreteDecoratorA );//装饰成A以后再装饰成B
concreteDecoratorB .method() ;
concreteDecoratorB .methodB() ;//装饰成B以后新增的方法
System.out.println("----------------------");
}
输出结果,由此可见可以扩展很多其他功能
3、io流中的使用
举例:InputStream是一个抽象类,相当于统一接口(Component),是装饰类和被装饰类的基本类型
FileInputStream相当于原始的待装饰对象,为具体实现类,也是被装饰类,本身具有很多完整功能
BufferedInputStream是一个具体的装饰器类,扩展了特有的方法
import java.io.*;
public class IODecorator {
public static void main(String[] args) throws IOException , FileNotFoundException {
final String filepath="F://a.txt";
/**
* InputStream相当于统一接口,是装饰类和被装饰类的基本类型(Component)
* FileInputStream相当于原始的待装饰的对象,为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类
*
*/
InputStream inputStream =new FileInputStream(filepath );
System.out.println("FileInputStream不支持mark和reset"+inputStream .markSupported() );
System.out.println("-----------------------");
/**
* 下面展示一种装饰器的作用BufferedInputStream
*
* BufferedInputStream是一个具体的装饰器类
* 其定义如下:
* BufferedInputStream extends FilterInputStream
*
* FilterInputStream是装饰类,其继承自InputStream
* 内部存在一个inputStream实例
*
* BufferedInputStream提供了特有的方法:
*/
BufferedInputStream bufferedInputStream =new BufferedInputStream(inputStream ) ;
System.out.println("bufferedInputStream支持mark和reset:"+bufferedInputStream .markSupported() );//提供实现自由的方法
bufferedInputStream .mark(0);//标记一下
char c=(char )bufferedInputStream .read() ;
System.out.println("文件的第一个字符:"+c);
bufferedInputStream .reset() ;//重置
c=(char )bufferedInputStream .read() ;//再读
System.out.println("重置以后再读一个字符,依然会是第一个字符:"+c);
bufferedInputStream .reset() ;
}
}
二、适配器模式
1、适配器介绍
Adapter:将一个类的接口转化成客户希望的另外的一个接口,Adapter模式使原来接口不兼容,不能一起工作的类可以一起工作
实现方式:类适配器和对象适配器
1、使用继承(就是所谓的类适配器)需要适配的类
2、使用组合(所谓的对象适配器)通过在内部包装一个Adaptee对象,把源接口转换成目标接口
例如:家用电源220v,而手机只需要5v,这就是一个适配过程
适配器所涉及的角色有:
Target(目标接口):所要转换的所期待的接口(5V)
Adaptee(源角色):需要适配的类220V
Adapter(适配器):将源角色适配成目标接口,一般持有源接口的引用(或者继承源接口),且实现目标接口(220——5)
Client(客户类):通过目标角色获取服务
适配器的特点:
1)通过继承或者内部封装adaptee对象,完成适配
2)有更好的复用性。系统需要使用现有的类,但此类接口不符合系统需要,通过适配器模式让这些功能得到很好的复用
2、代码实现
a、首先建立一个客户需要的目标接口
/**
* TypeC接口
* 即需要的目标接口(客户希望)
*/
public interface TypeC {
void isTypeC();
}
b、然后创建一个类可以实现客户希望的功能
/**
*
* 存在一个USB充电口
* 该充电口已经实现其特定的USB接口的能力
*/
public class USB {
void isUSB(){
System.out.println("use充电口");
}
}
c、第一种方式类适配器
将USB适配成TypeC
/**
* 类适配器
* 核心类:将USB适配成TypeC
*/
public class ClassAdapter extends USB implements TypeC {
@Override
public void isTypeC() {
//TypeC接口的实现是通过适配USB实现的
super .isUSB() ;
}
}
d、第二种方式对象适配器
将适配器的对象作为适配器的属性,通过构造函数获取实例
/**
* 对象适配器
* 将被适配的对象作为适配器的属性,通过构造函数获取实例
*/
public class ObjectAdapter implements TypeC {
private USB usb ;
public ObjectAdapter(USB usb){
this.usb=usb;
}
@Override
public void isTypeC() {
usb .isUSB() ;
}
}
d、Dome,应用
public class Client {
public static void main(String[] args) {
//类适配器的实现
TypeC typeC =new ClassAdapter() ;
//通过TypeC提供服务
typeC .isTypeC() ;
//对象适配器的实现
USB usb =new USB() ;
TypeC typeC1 =new ObjectAdapter(usb ) ;
typeC1 .isTypeC() ;
}
}
3、适配器在IO流中的使用
例如:
适配器角色就是InputStreamReader,(220——5)
被适配角色是InputStream类代的实例对象adaptee(220v)
目标接口是Reader类(5)
//目标类
public abstract class Reader implements Readable,Closeable
//需要适配的类
public abstract class InputStream implements Closeable
//转换流 适配器类
//InputStreamReader 操作字节
public class InputStreamReader extends Reader{
//解码类
private final StreamDecoder sd;
public InputStreamReader(InputStream in){
super(in);
try{
sd=StreamDecoder.forInputStreamReader(in,this,(String)null);
}catch(UnsupportedEncodingException e){
throw new Error(e);
}
}
int read(char cbuf[],int offset,int length) throws IOException{
return sd.read(cbuf,offset,length);
}
}
举例:(和对象适配器的用法相同)
File file =new File("hello.txt");
FileInputStream in=new FileInputStream(file);
//将FileInputStream适配成InputStreamReader,即输入的字节流转换成字符流
Reader inReader = new InputStreamReader(in);
三、装饰器和适配器的异同点
装饰器与适配器都有一个别名叫做 包装模式(Wrapper),它们看似都是起到包装一个类或对象的作用,但是使用它们的目的不相同
适配器模式:是要将一个接口转变成另外一个接口,它的目的是通过改变接口来达到重复使用的目的
装饰器模式:不是要改变被装饰对象的接口,而是恰恰要保持原有的接口,但是增强原有对象的功能
或者改变原有对象的处理方式而提升性能。所以这两个模式设计的目的是不同的