1 概述
装饰者模式的目的是给类的弄能增强。
继承也能给类的功能增强。
2 举例说明(便于观察和理解装饰模式)
Writer类是写文件的类,有三个子类,TxtWriter,MP3Writer,AVIWriter
在writer中定义了写文件的标准,三个子类分别去实现Writer中的写方法
使用继承方式来对类增强
Writer
|-----TxtWriter
|-----MP3Writer
|-----AVIWriter
如果写文件的缓冲区是同样的原理,那么我们就可以把缓冲区抽取出来作为装饰器。
三个普通类
AviWriter.java
package cn.tx.demo;
public class AviWriter {
public void write() {
System.out.println("写avi文件完成");
}
}
Mp3Writer.java
package cn.tx.demo;
public class Mp3Writer {
public void write() {
System.out.println("写mp3文件完成");
}
}
TxtWriter.java
package cn.tx.demo;
public class TxtWriter {
public void write() {
System.out.println("写txt文件完成");
}
}
需求,比如想给TxtWriter,MP3Writer,AVIWriter类的write的方法进行加强,给这三个write方法加一个缓冲的步骤。
2.1 方式一:继承
创建一个Writer类
Writer.java
package cn.tx.demo;
public class Writer {
public void buffer() {
System.out.println("助力的高效缓冲");
}
}
让每一个类都继承这个Writer类后
AviWriter.java
package cn.tx.demo;
public class AviWriter extends Writer{
public void write() {
buffer();
System.out.println("写avi文件完成");
}
}
Mp3Writer.java
package cn.tx.demo;
public class Mp3Writer extends Writer{
public void write() {
buffer();
System.out.println("写mp3文件完成");
}
}
TxtWriter.java
package cn.tx.demo;
public class TxtWriter extends Writer{
public void write() {
buffer();
System.out.println("写txt文件完成");
}
}
Test.java
package cn.tx.demo;
public class Test {
public static void main(String[] args) {
TxtWriter tw = new TxtWriter();
tw.write();
}
}
输出结果为:
助力的高效缓冲
写txt文件完成
结论:这种继承的方式需要改变每个类中的方法,对类中的方法有了侵略性。而我们想在不改变原有的东西的基础上,加强这个功能。
2.2 方式二:装饰者模式
角色:
1.抽象角色(定义写文件标准):Writer
2.具体的角色(实现写文件标准):三个子类TxtWriter,MP3Writer,AVIWriter
3.装饰角色[抽象](高效缓冲区):注意:也可以定义成抽象的,如果是抽象的就必须要有具体抽象角色
4.具体的装饰角色:来实现抽象装饰器中的增强方法。
代码实现:
目录结构
Writer.java
package cn.tx.demo;
public abstract class Writer {
public abstract void write() ;
}
AviWriter.java
package cn.tx.demo;
public class AviWriter extends Writer{
public void write() {
System.out.println("写avi文件完成");
}
}
TxtWriter.java
package cn.tx.demo;
public class TxtWriter extends Writer{
public void write() {
System.out.println("写txt文件完成");
}
}
Mp3Writer.java
package cn.tx.demo;
public class Mp3Writer extends Writer{
public void write() {
System.out.println("写mp3文件完成");
}
}
BufferTxWriter.java
package cn.tx.demo;
public class BufferTxWriter extends Writer{
//定义一个Writer属性
Writer writer;
public BufferTxWriter(Writer writer) {
this.writer = writer;
}
@Override
public void write() {
//先来调用装饰方法
buffer();
//调用实际的写方法
writer.write();
}
/*
* 装饰方法
*/
public void buffer() {
System.out.println("加上高效的缓冲");
}
}
Test.java
package cn.tx.demo;
public class Test {
public static void main(String[] args) {
Writer writer = new BufferTxWriter(new AviWriter());
writer.write();
System.out.println("--------------------------------");
writer = new BufferTxWriter(new TxtWriter());
writer.write();
System.out.println("--------------------------------");
writer = new BufferTxWriter(new Mp3Writer());
writer.write();
}
}
输出结果为:
加上高效的缓冲
写avi文件完成
--------------------------------
加上高效的缓冲
写txt文件完成
--------------------------------
加上高效的缓冲
写mp3文件完成
3 案例 23:00
3.1 案例需求
拷贝图片,拷贝文本......,在这个基础之上,加上一个拷贝文件的时候加上日志记录,考一个记一个,要求自动完成,不能手动完成。用装饰模式。
需要拷贝的文件:
拷贝到工程下的txfile文件夹下
实现代码:
Copy.java
package cn.tx.demoeg;
public abstract class Copy {
public abstract void copy(String fileName) throws Exception;
}
BinCopy.java
package cn.tx.demoeg;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class BinCopy extends Copy{
@Override
public void copy(String fileName) throws Exception {
FileInputStream in = new FileInputStream("d:\\res\\"+fileName);
FileOutputStream out = new FileOutputStream("txfile\\"+fileName);
byte[] bs = new byte[1024];
while(in.read(bs) != -1) {
out.write(bs);
}
out.close();
in.close();
}
}
TxtCopy.java
package cn.tx.demoeg;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
public class TxtCopy extends Copy{
@Override
public void copy(String fileName) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("d:\\res\\"+fileName));
PrintWriter pw = new PrintWriter("txfile\\"+fileName);
String line = null;
while((line = br.readLine()) != null){
pw.print(line);
}
pw.close();
br.close();
}
}
LogCopy.java
package cn.tx.demoeg;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LogCopy extends Copy{
private Copy copy;
public LogCopy(Copy copy) {
super();
this.copy = copy;
}
@Override
public void copy(String fileName) throws Exception {
copy.copy(fileName);
log(fileName);
}
/*
* 把拷贝的文件的记录都记在record.log里面
*/
public void log(String fileName) throws IOException {
//创建文件输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("record.log",true));
String str = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+ "--拷贝了文件--" +fileName;
bw.write(str);
bw.newLine();
bw.flush();
bw.close();
}
}
Test.java
package cn.tx.demoeg;
public class Test {
public static void main(String[] args) throws Exception {
LogCopy logCopy = new LogCopy(new BinCopy());
logCopy.copy("rz.jpg");
logCopy = new LogCopy(new TxtCopy());
logCopy.copy("test.txt");
}
}
输出结果:
record.log
2021-04-17 12:36:59--拷贝了文件--rz.jpg
2021-04-17 12:38:34--拷贝了文件--rz.jpg
2021-04-17 12:38:34--拷贝了文件--test.txt
后续如果再想追加拷贝别的东西的方法,直接在新类Xxx.java中写自己拷贝的功能就行了,然后直接继承一下Copy类。
使用的时候还是和别的一样用,就带有日志记录功能。
试验:
在Test类中用
logCopy = new LogCopy(new Xxx());
logCopy.copy("要拷贝的文件名");
结果一样是可以在record.log中写下日志。