jeudi 17 septembre 2015

How to make a service method handle subclasses specificities

I have an application witch has to handle multiple types of documents.

I have a service generateReport(DocumentEntity) witch has to build a report, this service will be called for every types of child of DocumentEntity.

The thing is that the report we want to build depends on the type of document.

My code bellow works but I feel like there is a better way to do it :

Lets say we have DocumentDonationEntity & DocumentBookEntity witch extends DocumentEntity :

public abstract class DocumentEntity {
    protected Long id;
    protected String name;
    // getters & setters
}

public class DocumentDonationEntity extends DocumentEntity {
    private String donatorName;
    // getters & setters
}

public class DocumentBookEntity extends DocumentEntity {
    private Long price;
    // getters & setters
}

And ReportDataBook & and ReportDataDonation witch extends ReportData :

public abstract class ReportData {
    protected Long id;
    protected String name;

    public void checkNotNull() throws MyException {
        if this.id == null
            throw new myException();
        if this.name == null
            throw new myException();
        // other generic stuff
    }
    // getters & setters
}

public class ReportDataBook extends ReportData {
    private String price;

    public void checkNotNull() throws MyException {
        super.checkNotNull();
        if this.price == null
            throw new myException();
        // other stuff specific to books
    }
    // getters & setters
}

public class ReportDataDonation extends ReportData {
    private String donatorName;

    public void checkNotNull() throws MyException {
        super.checkNotNull();
        if this.donatorName == null
            throw new MyException();
        // other stuff specific to donations
    }
    // getters & setters
}

Plus a utils class :

public class Utils {
    public ReportData fillReport(DocumentEntity document) throws Exception {
        if (document instanceof DocumentBookEntity) {
            ReportDataBook data = new ReportDataBook();
            completeReportData(data, (DocumentBookEntity) document);
            completeReportData(data, document);
            return data;
        } else if (document instanceof DocumentDonationEntity) {
            ReportDataDonation data = new ReportDataDonation ();
            completeReportData(data, (DocumentDonationEntity) document);
            completeReportData(data, document);
            return data;
        }
        return null;
    }

    public void completeReportData(ReportData data, DocumentEntity document) {
        // some generic stuff
    }

    public void completeReportData(ReportDataBook data, DocumentBookEntity document) {
        // some stuff specific to books
    }

     public void completeReportData(ReportDataDonation data, DocumentDonationEntity document) {
        // some stuff specific to donations
    }

}

Then I have a Service :

@Service
public class MyService implements IMyService {

    @Override
    public boolean generateReport(DocumentEntity document) throws MyException {
        ReportData data = initializeReport(document);
        // do some other stuff
    }

    private ReportData initializeReport(DocumentEntity document) throws myException {
        if (document instanceof DocumentBookEntity) {
            ReportDataBook data = (ReportDataBook) utils.fillReport(document);
            data.checkNotNull();
            return data;
        } else if (document instanceof DocumentDonationEntity) {
            ReportDataDonation data = (ReportDataBook) utils.fillReport(document);
            data.checkNotNull();
            return data;
        }
        return null;
    }
}

Aucun commentaire:

Enregistrer un commentaire