装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供加强功能。那么,自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的类,并基于被装饰的对象的功能,提供更强的功能。
装饰和继承的区别:
装饰模式:
MyReader // 专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader // 装饰类:增强MyReader 读取功能。
此时 MyBufferReader 类如:
class MyBufferReader extends MyReader { MyBufferReader(MyReader r){ } }
继承:
MyReader // 专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
class MyBufferReader { MyBufferReader(MyTextReader text) {} MyBufferReader(MyMediaReader media){} 如果要添加子类。如MyBufferDataReader。则要修改此处的代码。。。 所以使用继承的话,代码不安全。 }
通过如上的比较,可以知道:装饰模式比继承要灵活。避免了继承体系的臃肿,而且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常都属于一个体系中的。
模拟: BufferedReader 类,并完成其的特用方法 readLine() ;
> readLine() : 每次读一行数据。
1 import java.io.*; 2 public class MyBufferedReader { 3 private FileReader fr = null ; 4 public MyBufferedReader(FileReader fr) { 5 this.fr = fr ; 6 } 7 // 模拟 readLine 方法,一次读一行 8 public String MyReadLine() throws IOException{ 9 // 定义一个临时容器 10 StringBuilder sb = new StringBuilder() ; 11 int ch = 0 ; 12 while ((ch = fr.read()) != -1) { 13 if (ch == '\r') 14 continue ; 15 if (ch == '\n') 16 return sb.toString() ; 17 sb.append((char)ch) ; 18 } 19 if (sb.length() != 0) 20 return sb.toString() ; 21 return null ; 22 } 23 public void myClose() throws IOException { 24 fr.close() ; 25 } 26 }
模拟:BufferedInputStream 类,自定义MyBufferedInputStream 类。
首先:分析BufferedInputStream 类的原理:1、从硬盘上读取数据到缓冲区(new FileInputStream("....").read(buf) ;) 。
2、从缓冲区读取数据。
1 import java.io.*; 2 public class MyBufferedInputStream { 3 private InputStream in ; 4 5 // 定义容器: 6 private byte[] buf = new byte[1024] ; 7 // 定义计数器: 8 private int pos = 0 ; 9 private int count = 0 ; 10 11 MyBufferedInputStream(InputStream in ) { 12 this.in = in ; 13 } 14 15 // 一次读一个字节,从缓冲区(字节数组)获取。 16 public int MyRead() throws IOException { 17 // 通过in对象读取硬盘上数据,并存储buf中。 18 if(count == 0) { 19 count = in.read(buf) ; 20 if (count < 0) 21 return -1 ; 22 pos = 0 ; 23 byte b = buf[pos] ; 24 25 count -- ; 26 pos ++ ; 27 return b&255 ; 28 } 29 else if (count >0) { 30 byte b = buf[pos] ; 31 32 count -- ; 33 pos ++ ; 34 return b&255 ; 35 } 36 return -1 ; 37 } 38 public void MyClose() throws IOException { 39 in.close() ; 40 } 41 }
上述代码:buf 用来存储从硬盘中读取的数据;其中返回int 型则是对 byte 数据的提升。 因为b 是byte 型,转换成int 型时,前面会自动补1,而为了避免补1,所以与255相& 。
在定义功能方法时,不用使用try ,直接抛出异常。