diegosasw
diegosasw

Reputation: 15694

Which design pattern to use when modelling something that can contain different properties

I've got a design dilemma.

I have to perform CRUD operations on an entity. Let's call it Report

public class Report 
{
   public Guid Id { get; set;}
   public string Name { get; set;}
   public ReportType ReportType { get; set;}
   //public ?? DetailsTypeSpecific { get; set;} //how to model?

}

A Report can be of a specific type that represents what kind of information is going to inform about.

public enum ReportType 
{
   DownloadsInfo = 1,
   ClicksInfo = 2,
   UploadsInfo 3
}

depending on this type, some reports will contain certain data (in the property DetailsTypeSpecific) and some others will contain other data. For example a Report with type DownloadsInfo will contain things like:

and the reports of type ClicksInfo could have other kind of information. For example:

etc.

A Report will have a button to be exported as an excel file. In other words, a report is excelExportable and I need to provide different implementation for the excel generator depending on the report's type.

Also, the data that the Report contains needs to be added to the Report class as a property, and here's the problem. I don't know how to model it.

Sometimes I will need to retrieve Reports from database, and I need to deserialize its details into an appropriate object.

should I make Report generic where the T represents the type of object it stores?

Should I add a property of type object to the report and somehow have the deserialization/casting as an external functionality

I just know that:

Is there any design pattern that could help me with getting my head around this kind of problems?

UPDATE 1: I think I haven't explained the problem properly. The key is in my second restriction, I don't know what type of Report I am dealing with.

I am storing reports in a no-SQL database (MongoDB without schema, which is storing objects Report and in the property DetailsTypeSpecific it can go anything, any object of any shape).

Suppose I want to retrieve a report with certain Id. I go:

var report = _myRepo.GetReport("12f06eb1-213b-49af-9d41-44b25180aae9");

I want to be able to do

report.Export();

I cannot really use inheritance/polymorphism because I simply didn't deserialize my Json database record into any appropriate Report sub-type that would contain the excel generator, and polimorphism assumes I "know" already the subtype.

I could have an external export service that depending on the type uses one generator or another and do:

var exportedFile = _myExportService.Export(report);

That means that each time I add a new ReportType I have to modify MyExportService to add support for it. I wanted something more respectful of the open-close principle.

The main problem here is to have something generic to store data in Report that depends on the ReportType. That's what I don't know how to model.

Upvotes: 0

Views: 344

Answers (1)

David Osborne
David Osborne

Reputation: 6821

Why can't you use plain old inheritance?

Something like:

public abstract class Report
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    // You might be able to replace this polymorphism
    public ReportType ReportType { get; set; }

    public abstract Report Export();
}

public class DownloadsInfoReport : Report
{
    public object FileFormat { get; set; }

    public bool IsInCloud { get; set; }

    public string DownloadedThroughLink { get; set; }

    public override Report Export()
    {
        // Specific Export logic here
    }
}

public class ClicksInfoReport : Report
{
    public object UserClicking { get; set; }

    public int TimesClickedOnSamePage { get; set; }

    public override Report Export()
    {
        // Specific Export logic here
    }
}

Then you get the ability to do something like:

foreach (var report in allReports)
{
    report.Export();
}

Upvotes: 2

Related Questions