Reputation: 15694
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
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