Java design pattern Decorator Pattern

Keywords: ftp Excel SQL

1, Scenario description

(1) Questions

In the system, Crystal Report tool is used to generate reports initially, and the reports are sent to the client for viewing. At this time, defining a Crystal Report tool class can complete the generation of crystal reports.

The SSRS report service is added to subsequent report tools. At this time, the SSRSReport tool class can be defined to complete the generation of SSRS reports;

And define the Report interface, reconstruct the two Report tool classes to realize the Report interface, and the client calls through the interface.

The requirement then changes. The report tool needs to export an editable version of Word while sending it to the client (in PDF format). For this, we can define four tool classes: CrystalReportPDF, CrystalReportWord, SSRSReportPDF, and SSRSReportWord to implement corresponding functions.

The requirements continue to change. The report tool needs to be able to store the report on the File System while sending it to the client (in Word format or PDF format). You can define CrystalReportPDF, CrystalReportPDF2FS, CrystalReportWord, CrystalReportWord2FS... For this.

The demand is still changing. The report tool has added the Fine Report (sail soft report). It is required to store it on the FTP server and send it to the designated user by email at the same time of output. The output format needs Excel

(2) Solutions

For this scenario, the previous method is very painful (implementing the interface by defining the class), at this time, you can apply the decorator pattern.

There are three kinds of Report tools, namely Crystal Report, SSRS and Fine Report. Therefore, three classes can be defined to implement the Report interface.

Export to Word version, export to Excel version, store to file system, store to FTP server, mail sending user, etc. can be understood as decoration of report tool.

Therefore, you can define decoration classes of various reportgenerators to add decoration to report tool classes (one of the three specific ones) (multiple decorations can be added, and can be added multiple times).

According to this definition, the parent class ReportGenerator of decoration class is defined to hold the Report interface object and implement the Report interface, so that the decoration can be added to the held object and finally the decorated method can be published.

Next, define classes for different types of decorators, inherit the parent class ReportGenerator, for example, define the ExportWordReport class, so that it can output Word format reports, and define StorageReport2FTP class, so that it can store reports to the FTP server.

On the call side, you can create a report of a certain type (one of the three report services), and call different combinations of decorator classes to realize the function of dynamic extension classes. For example, if you call ExportWordReport, ExportExcelReport and StorageReport2FTP, you can output the report as Word and Excel and store it in the FTP server.

In addition, suppose there is a decoration function, which sends the report generation notice to the user in the form of Email, SMS, APP notice, etc. because the message needs to be processed when it is sent, a common generation message decoration class can be defined. At this time, the decoration class can define the parent-child class to inherit continuously.

The advantage of decorator is that it extends class functions dynamically (compared with defining specific classes to implement interfaces), abstracts decorating functions into decorating classes, reduces the number of implementing classes, reduces the complexity, and is more in line with the natural situation of objects (I think the way to distinguish decorating classes and subclasses is that decorating can be added or not, one can be added or added repeatedly, while subclasses Class has and only one; for example, when eating, noodles, steamed bread, rice as the main food, general people choose one of them, which can be realized as a sub class, while scrambled vegetables such as scrambled eggs with tomatoes, fried fungus with cucumbers and so on can add two or three, or even two scrambled eggs with tomatoes, so scrambled vegetables can be used as decoration class).

The disadvantage of the decorator is that the number of layers of decoration can be different, so it is more complex in troubleshooting. For example, a wall is added with N layers of wallpaper and painted with N layers of paint. Now it's a little difficult to troubleshoot where the crack is on the wall.

2, Sample code

Interface:

package lims.designpatterndemo.decoratedemo;

public interface Report {
    public String generateReport();
}

Crystal Report report report tool class:

package lims.designpatterndemo.decoratedemo;

public class CrystalReport implements Report {

    @Override
    public String generateReport() { 
        return "Generate Report using Crystal Report!";
    }

}

SSRS report tool class:

package lims.designpatterndemo.decoratedemo;

public class SSRSReport implements Report {

    @Override
    public String generateReport() { 
        return "Generate Report using Sql Server Report Service!";
    } 
}

Fine Report report report tool class:

package lims.designpatterndemo.decoratedemo;

public class FineReport implements Report {

    @Override
    public String generateReport() { 
        return "Generate Report using Fine Report!";
    }
    
}

Decoration class parent class:

package lims.designpatterndemo.decoratedemo;

public class ReportGenerator implements Report {
    //Hold interface
    private Report report;
    public ReportGenerator(Report report){
        this.report = report;
    }
    
    @Override
    public String generateReport() { 
        return report.generateReport();
    }
    
}

Output Word report decoration class:

package lims.designpatterndemo.decoratedemo;

public class ExportWordReport extends ReportGenerator{
    public ExportWordReport(Report report) {
        super(report); 
    }
    public String generateReport() { 
        return super.generateReport() + " Export to Word Format!";
    }
}

Output Excel report decoration class:

package lims.designpatterndemo.decoratedemo;

public class ExportExcelReport extends ReportGenerator{
    public ExportExcelReport(Report report) {
        super(report); 
    }
    public String generateReport() { 
        return super.generateReport() + " Export to Excel Format!";
    }
}

Store report to FTP server decoration class:

package lims.designpatterndemo.decoratedemo;

public class StorageReport2FTP extends ReportGenerator{
    public StorageReport2FTP(Report report) {
        super(report); 
    }
    public String generateReport() { 
        return super.generateReport() + " Storage Report to FTP Server!";
    }
}

Dynamic call:

package lims.designpatterndemo.decoratedemo;

public class DecorateDemo {
    public static void main(String args[]){
        Report report = new CrystalReport();  
        report = new ExportWordReport(report);
        report = new ExportExcelReport(report);
        report = new StorageReport2FTP(report); 
        System.out.println(report.generateReport());
    } 
}

Output results:

Generate Report using Crystal Report! Export to Word Format! Export to Excel Format! Storage Report to FTP Server!

Send notification message decoration class:

package lims.designpatterndemo.decoratedemo;

public class SendReport extends ReportGenerator {

    public SendReport(Report report) {
        super(report); 
    }
    
    public String generateReport() { 
        return super.generateReport() + " Send Report!";
    }
}

Send a message to the Email decoration class:

package lims.designpatterndemo.decoratedemo;

public class SendReport2Email extends SendReport {

    public SendReport2Email(Report report) {
        super(report); 
    }
    
    public String generateReport() { 
        return super.generateReport() + " send to Email!";
    }
}

Call test:

package lims.designpatterndemo.decoratedemo;

public class DecorateDemo {
    public static void main(String args[]){
        Report report = new CrystalReport();  
        report = new ExportWordReport(report);
        report = new ExportExcelReport(report);
        report = new StorageReport2FTP(report); 
        report = new SendReport2Email(report);  
        System.out.println(report.generateReport());
    } 
}

Output results:

Generate Report using Crystal Report! Export to Word Format! Export to Excel Format! Storage Report to FTP Server! Send Report! send to Email!

My blog is about to be moved and synchronized to Tencent cloud + community. Please join us: https://cloud.tencent.com/developer/support-plan?invite_code=2ui9qt2awpwkg

My blog will be moved to Tencent cloud + community soon, and we invite you to join us: https://cloud.tencent.com/developer/support-plan?invite_code=2ui9qt2awpwkg

Posted by luzlin on Mon, 20 Apr 2020 20:36:51 -0700