I/O流的装饰器

585

分析

Java的IO流粗略架构如下:

Java的IO流就是利用了装饰模式,这在我们平时使用的时候也能感觉出来,每次的输入输出都要一层层的“装饰”才能使用。 为了实现将输入的英文加密后再存储到文本文件里,其实我们可以选择多个装饰的“层”。 我选择了输出流中的 FilterOutputStream进行了装饰,即在接收到了控制台的输入之后,首先进行加密转换,然后再调用基类的方法写入到文件中去。

UML图:

总结:

装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。是继承关系的一个替代方案。

**优点:**装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

  1. 比静态继承更灵活: 与对象的静态继承(多重继承)相比, Decorator模式提供了更加灵活的向对象添加职责的方式。
  2. Decorator与它的Component不一样 Decorator是一个透明的包装。
  3. 避免在层次结构高层的类有太多的特征 Decorator模式提供了一种“即用即付”的方法来添加职责。

**缺点:**多层装饰比较复杂。采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

代码:

类图:

1、 装饰类EncryptionEnglish,继承了FilterOutputStream,重写了write方法,实现对写入内容的加密。

package medemede;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
//文件写入过程的装饰类,装饰了FilterOutputStream
public class EncryptionEnglish extends FilterOutputStream {

    EncryptionEnglish(OutputStream out) {
        super(out);
    }
    @Override //重写了write方法,对ASCII码循环加2
    public void write(int x) throws IOException {
        if(x<91){
            if(x+2>90)
                x=x-26+2;
            else
                x=x+2;
        }else {
            if(x+2>122)
                x=x-26+2;
            else
                x=x+2;
        }
        super.write(x);  //调用基类方法写入文件中
    }
}

2、 装饰类Decrypted,继承了FileInputStream,重写了read方法,实现对文件内容的解密输出。

package medemede;
import java.io.*;
//文件读取过程的装饰类,装饰了FileInputStream
public class Decrypted extends FileInputStream {
    public Decrypted(String name) throws FileNotFoundException {super(name);}
    public Decrypted(File file) throws FileNotFoundException {super(file);}
    public Decrypted(FileDescriptor fdObj) {
        super(fdObj);
    }

    @Override  //重写了read方法,对内容循环减2
    public int read() throws IOException {
        int x=super.read();  //调用基类方法获取字节
        if(x==-1)
            return x;
        else {
            if(x<91){
                if(x-2<65)
                    x=x+24-2;
                else
                    x=x-2;
            }else {
                if(x-2<97)
                    x=x+24-2;
                else
                    x=x-2;
            }
            return x;
        }
    }
}

3、 客户端,实现加密输入与解密输出

package medemede;
import java.io.*;
import java.util.Scanner;

public class  Main {
    public static void main(String[] args) {

        //从键盘接受字节并写入test.txt
        Scanner in=new Scanner(System.in);
        OutputStream outputStream=null;
        String str;
        try {
            outputStream=new EncryptionEnglish(new BufferedOutputStream(new FileOutputStream(new File("test.txt"))));
            str=in.next();
            outputStream.write(str.getBytes());
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                assert outputStream != null;
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //从test.txt中读取数据,并解密输出
        FileInputStream fis;
        try {
            int len;
            //调用的原FileInputStream
            FileInputStream fisOld=new FileInputStream("test.txt");
            System.out.print("文件内的加密内容:");
            while ((len = fisOld.read()) != -1) {
                System.out.print((char)len);
            }
            System.out.println();

            //调用的装饰类Decrypted
            fis = new Decrypted("test.txt");
            System.out.print("文件内容解密:");
            while ((len = fis.read()) != -1) {
                System.out.print((char)len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

4、 输出