Developing a C# POP3 client: Part 07 - Design considerations and some refactoring

This is number seven in a series of posts on developing a POP3 client in C#. These are the previous posts on this topic:

It's quite a while since my last "real" post about my POP3 client project. Along some other projects I'm working on, I noticed that I had to reconsider some of my design decisions. Some months ago, in March or April I read the (by the way very recommendable) book Head First Design Patterns. One thing that is pointed out very clearly is to "coding to interfaces, not to concrete implementations". While I had that in mind I didn't get an overall picture of the project and which interfaces and classes are really needed and how they relate. In the last couple of weeks I also dealt with Dependency Inversion, Inversion of Control and Dependency Injection.

So I made some thoughts about how to achieve a larger flexibility and less "hard coded" dependencies between the different classes. Also another fact forced me to rethink my design. While programming the code for converting string MIME data to MailMessage classes, I came at a point where I had to add a reference in Opo.Net.Mime to Opo.Net.Mail but got the error "circular reference" because I already had a reference from Opo.Net.Mail to Opo.Net.Mime:

I decided to change the MimeEntity to only hold string values and to add a MailMessageConverter class that then converts the MimeEntity to a MailMessage. Furthermore I wanted to let the user plug in custom MIME parsers and converters for other formats (e.g. XML). For that purpose I introduced the interfaces IMimeParser and IMailMessageConverter. For now I implemented the RegexMimeParser class (uses regular expression to parse the MIME data), a MimeMailMessageConverter (not fully implemented now) and a XmlMailMessageConverter.

Lets have a look at some code samples:

// download a message from a server and then convert it to MailMessage instance
using Opo.Net.Mail;
using Opo.Net.Mime; 

// MimeMailMessageConverter uses default IMimeParser (RegexMimeParser)
public void LoadMessage()
{
	Pop3Client pop3Client = new Pop3Client("example.org", 25);
	string mimeData = pop3Client.GetMessage(1);
	IMailMessageConverter mailMessageConverter = new MimeMailMessageConverter();
	IMailMessage mailMessage = mailMessageConverter.ConvertFrom(mimeData);
}

// MimeMailMessageConverter uses custom IMimeParser
public void LoadMessage()
{
	Pop3Client pop3Client = new Pop3Client("example.org", 25);
	string mimeData = pop3Client.GetMessage(1);
	IMailMessageConverter mailMessageConverter = new MimeMailMessageConverter();
	IMimeParser mimeParser = new RegexMimeParser();
	IMailMessage mailMessage = mailMessageConverter.ConvertFrom(mimeParser, mimeData);
}

The MimeMailMessageConverter uses IMimeParser and IMimeEntity internally. May the converter interface will change to something like this, but I'm not sure if this makes more sense...

public interface IMailMessageConverter
{
	IMailMessage ConvertFrom(ref IMailMessage, object data);
	object ConvertTo(ref IMailMessage, IMailMessage mailMessage);
	IMailMessage LoadFromFile(string path);
	string SaveToFile(IMailMessage mailMessage, string path);
	string SaveToFile(IMailMessage mailMessage, string path, string fileName);
}

This is what the dependencies look now:

Get the updated source on Codeplex: http://www.codeplex.com/OpoNet


Posted by: Dave
Posted on: 10/21/2008 at 8:40 PM
Tags: , , Categories: Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed
Administration: