Alexander Derck
Alexander Derck

Reputation: 14488

Abstract class with private derived classes: implement method for some

I made a class to generate 2 similar but yet very different reports. For that I used the pattern I found here: https://stackoverflow.com/a/29907649/3410196 It uses an abstract baseclass, which contains private derived classes with public constructors, so other code can never actually access the constructors of the derived class, and only create objects by using the static Create() method.

Now I'm facing a problem: Everything works fine and I can export the reports etc. But now I have to be able to export one of the reports in a different format. Is there any way I can make this method accessible through the base class only for that one derived class? Otherwise I'll have to throw new NotImplementedException() or force my users to use something like this:

//Is actually multiReport (multireport:report)
Report report = Report.Create(...);
MemoryStream stream = (report as multireport).ExportOtherFormat();

I doubt this is possible but maybe there is a way!

Upvotes: 0

Views: 185

Answers (3)

Alexander Derck
Alexander Derck

Reputation: 14488

After all I went for a solution (maybe not the best) to make one of the classes public and expose the method like that, but not have it on the other subclasses:

abstract class Report
{
private Report() {}

public abstract MemoryStream ExportPDF() { ... }  

public class ReportA : Report
{
    public ReportA() { ... }
    public override MemoryStream ExportPDF() {...}
    public MemoryStream ExportCSV() {...}
}

private class ReportB : Report
{
    public ReportB() { ... }
    public override MemoryStream ExportPDF() {...}
}

public static Report Create() { ... }
}

Now only subclass A has the method ExportCSV() and shows it. Now people can call the constructor to make a sublcass A however, which I don't really like

Upvotes: 0

Gennadii Kurabko
Gennadii Kurabko

Reputation: 473

If I understood you correctly, you need something like that, so that ReportB will provide new implementation of Export method:

abstract class Report
{
    private Report() {}

    public virtual MemoryStream Export() { ... }  

    private class ReportA : Report
    {
        public ReportA() { ... }
    }

    private class ReportB : Report
    {
        public ReportB() { ... }
        new public virtual MemoryStream Export() { ... }
    }

    public static Report Create() { ... }
}

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726499

You cannot make a method of one of the subclasses visible to outside users, because they create an instance of the base class (i.e. basereport, not multireport). They wouldn't be able to call ExportOtherFormat unless they know that they are looking at an instance of multireport, not basereport.

One way to work around this issue is to hide the format decision from the users as well. Make an enum of formats, and make ExportWithFormat method that takes it:

[Flags]
enum ReportFormat {
    Simple    = 1
,   Extended  = 2
,   Special   = 4
,   Multifile = 8
}

Add these properties and methods to the base class:

public ReportFormat AvailableExportFormats { get {... } }

public MemoryStream ExportWithFormat(ReportFormat format);

Now your Multireport can return the special flag for the extra format that it supports in AvailableExportFormats, and produce the proper export when that flag is passed back to it in ExportWithFormat method.

Upvotes: 1

Related Questions