java设计模式_装饰者模式

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.具体的装饰角色:来实现抽象装饰器中的增强方法。

代码实现:

 

目录结构

java设计模式_装饰者模式

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 案例需求

拷贝图片,拷贝文本......,在这个基础之上,加上一个拷贝文件的时候加上日志记录,考一个记一个,要求自动完成,不能手动完成。用装饰模式。

需要拷贝的文件:

java设计模式_装饰者模式

拷贝到工程下的txfile文件夹下

java设计模式_装饰者模式

实现代码:

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");
    }
}

输出结果:

 

java设计模式_装饰者模式

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中写下日志。

上一篇:python中numpy数组保存为Excel文件


下一篇:Python csv存储