Decouple Data interchange format from Domain Model
I was doing a client app to display some data, the client receive data in xml format. One design constrain for me was, consumer’s domain model should have less impact even if the interchange format changes. So once the domain is loosely coupled, it can work on any type of data. The data can be in XML, JSON, or what ever it is. This post explains how I achieved it, it’s a very simple approach based on Strategy and Iterator Pattern.
For simplicity, I read the xml data from a file. Below is the xml
<Library> <Books> <Book Name="CLR via C#" Price="30"></Book> <Book Name="Algorithm Design Manual" Price="40"></Book> </Books> </Library>
Parsers
I created a parser class to parse the xml files. Below is the contract and the parser.
public interface IBookDetailsParser:System.Collections.IEnumerator { string getName(); double getPrice(); }
public class BookDetailsXMLParser:IBookDetailsParser { private int _nodeCount; private int _position; private XmlDocument _bookDetails; public BookDetailsXMLParser(XmlDocument bookDetails) { this._bookDetails = bookDetails; this._position = -1; this._nodeCount = _bookDetails.SelectNodes("/Library/Books/Book").Count; } public string getName() { return this.getValue("Name"); } public double getPrice() { return Convert.ToDouble(this.getValue("Price")); } private string getValue(string attributeName) { var node = _bookDetails.SelectSingleNode("/Library/Books/Book[" + (_position + 1).ToString() + "]/@" + attributeName); if (node == null) return string.Empty; return node.Value; } public object Current { get { return _bookDetails.SelectSingleNode("/Library/Books/Book[" + (_position + 1).ToString() + "]"); } } public bool MoveNext() { _position++; return (_position < _nodeCount); } public void Reset() { _position = -1; } }
As you can see the parser is based on the enumerator pattern.
Domain Model
public class Book { public Book(string name,double price) { this.Name = name; this.Price = price; } public string Name { get; private set; } public double Price { get; private set; } }
public class BookList { private IBookDetailsParser _bookDetailParser; public BookList(IBookDetailsParser bookDetailParser) { this._bookDetailParser = bookDetailParser; } public IList<Book> GetBooks() { IList<Book> books = new List<Book>(); while (_bookDetailParser.MoveNext()) { Book book = new Book(_bookDetailParser.getName(), _bookDetailParser.getPrice()); books.Add(book); } return books; } }
BookList is not aware of what kind of data format it operates on. In case of XML data we can inject the xml parser provided above. Later if we want to change to JSON format then write a json parser implemented by IBookDetailsParser and pass the new json parser to BookList. In this approach any change in data interchange format wont make any impact to our model.
BookService combine all these things together.
public class BookService { public IList<Book> GetAllBooks() { ServerDataReader dataReader=new ServerDataReader(); System.Xml.XmlDocument booksXML = dataReader.GetBooks(); BookList bookList = new BookList(new BookDetailsXMLParser(booksXML)); return bookList.GetBooks(); } }
Any change in the interchange format will affect the BookService. We can make it loosely coupled here as well but that’s not the intention of this post, here I just want to show a loosely coupled domain model from data format.
Could you write about Phsycis so I can pass Science class?
Mande
November 23, 2011 at 5:29 am