I have a calendar event object. I have plans to make it compatible with CalDAV/iCal/vCal protocols/file formats, which require the event be serialized and de-serialized to and from different formats.
I could write an ImportICal, ExportICal, ImportVCal, ExportVCal, etc. set of methods, but that doesn't seem like a very good approach, because what if the vCal format is updated, etc.
Has anyone dealt with this type of import/export situation before? If so, what design pattern (if any) is generally best?
Thanks for your help!
I am not particulary familiar with those formats but I'd create an simple data transfer object that represents your genereric calendar event object. It does nothing but holding the data (pseudocode):
class CalendarEvent
{
DateTime Date { get; }
string Title { get; }
string Description { get; }
}
Then you create an interface for CalendarEventReader and CalendarEventWriter (it's Strategy pattern and maybe the Builder pattern, sort of):
interface ICalendarEventReader
{
CalendarEvent Read(Stream data);
// Add additional methods if needed e.g.:
string GetTitleOnly(Stream data);
}
interface ICalendarEventWriter
{
Stream Write(CalendarEvent event);
// Add additional methods if needed e.g.:
Stream WriteSummaryOnly(CalendarEvent event);
}
Then have actual implementations implement the above interfaces. One for each format. You can even think about having reader and writer in the same class:
class CalDavConverter : ICalenderEventWriter, ICalendarEventReader
{
...
}
You'd then have a Repository (it's the Factory pattern maybe with Singleton) that maintains a list of ICalenderEventReader/Writer implementations for the different formats:
static class CalenderEventConverterRepository
{
static ICalendarEventReader GetReader(string formatName /*or any other data upon wich to decide wich format is needed*/)
{
...
}
static ICalendarEventReader GetWriter(string formatName /*or any other data upon wich to decide wich format is needed*/)
{
...
}
}
If the vCal format is updated, you will have to change whatever code you have written whichever design pattern you use (unless they decide to switch to something like ASN.1 where upgrades are baked in).
I would create a format interface with import and export methods, and possibly metadata and methods for testing whether a random bit of XML is likely to be that format. Then for each different format, you have an object which implements that interface. This is sort of a 'strategy design pattern', but each format represents several strategies for doing a cohesive set of things (import,export,detection) rather than having separate strategy objects.
Usual way to arrange multiple implementations (calendar protocols in your case) with a single common interface is Bridge Pattern.