装饰设计模式:
当想要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,基于已有对象的功能,并提供加强功能,那么自定义的该类就成为装饰类。
特点:装饰类通常会通过构造函数接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
例如:
public class MyBufferedReader {
private Reader r;
public MyBufferedReader(Reader r) {
super();
this.r = r;
}
//可以一次读取一行的方法
public String myReadLine() throws IOException
{
//定义一个临时容器。StringBulider容器,应用于存储字符数组
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=r.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
//复写reader中的抽象方法
//复写close方法
public void close() throws IOException
{
r.close();
}
//复写read方法
public int read (char[] c,int off,int len) throws IOException{
return r.read(c, off, len);
}
}
装饰和继承的区别:
装饰模式比继承要灵活,避免了继承体系臃肿。而且降低了类与类之间的关系。装饰类因为是增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常都属于一个体系中的。
MyReader专门由于读取数据的类,
LineNumberReader(BufferedReader子类)
跟踪行号的缓冲字符输入流。
方法:setLineNumber(int):设置当前行号。
getLineNumber():获取当前行号。
默认情况下,行编号从0开始,该行号随数据读取在每个行结束符处递增,并可以通过调用setLineNumber更改行号,但是,setLineNumber不会实际更改流中的当前位置,它主要更改将由getLineNumber()返回的值。
练习:模拟一个带行号的缓冲区对象。
class MyLineNumberReader{
private Reader reader;
private int lineNumber;
public MyLineNumberReader(Reader reader){
this.reader=reader;
}
public String MyReadLine() throws IOException{
lineNumber++;//每读取一行时,行数自动加1一次
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=reader.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void setLineNumber(int lineNumber){//设置行号
this.lineNumber=lineNumber;
}
public int getLineNumber(){//获取行号
return lineNumber;
}
public void myClose() throws IOException{
reader.close();
}
}
程序优化:由于缓冲区BufferedReader中已经实现了readLine和close方法,且在模拟读取字符流缓冲区时也自定义实现了readLine和close方法,在模拟带行号的缓冲对象时,再次实现readLine和close,代码重复,所以继承BufferedReader或者自定义的缓冲区类,可以减少代码的重复。
优化后的代码:
class MyLineNumberReader extends MyBufferedReader {
private int lineNumber;
public MyLineNumberReader(Reader r){
super(r);
}
public String MyReadLine() throws IOException{
lineNumber++;//每读取一行时,行数自动加1一次
return super.MyReadLine();
}
public void setLineNumber(int lineNumber){//设置行号
this.lineNumber=lineNumber;
}
public int getLineNumber(){//获取行号
return lineNumber;
}
}