November 23, 2010 Design Patterns
November 23, 2010 Design Patterns
Did you ever think why so many things around us have tree-similar structure? Top management of your company can delegate some work to middle management, and it can delegate it to your direct manager, who will ask you and your colleagues do something. In one of your tasks you had to gather data for some customer into xml. XML has also tree-similar structure. Why? Because it is the best way to serialize data, that can have data, that can… You got that! Now imagine that you want to gather data for some document part by part.
Composite is design pattern that provides us tree-similar structural representing of classes, this allows us work uniformly with parents and Childs.
So interface that defines common requirements for parents and kids:
public interface IDocumentComponent { string GatherData(); void AddComponent(IDocumentComponent documentComponent); }
And here we see some leaf component implementation. It is Customer Component, which gathers some data about customer basing on id provided to the class.
public class CustomerDocumentComponent : IDocumentComponent { private int CustomerIdToGatherData { get; set; } public CustomerDocumentComponent(int customerIdToGatherData) { CustomerIdToGatherData = customerIdToGatherData; } public string GatherData() { string customerData; switch (CustomerIdToGatherData) { case 41: customerData = "Andriy Buday"; break; default: customerData = "Someone else"; break; } return string.Format("<Customer>{0}</Customer>", customerData); } public void AddComponent(IDocumentComponent documentComponent) { Console.WriteLine("Cannot add to leaf..."); } }
And not-leaf implementation of the component below. Please take into account that it simply loops through Childs and executes GatherData method.
public class DocumentComponent : IDocumentComponent { public string Name { get; private set; } public List<IDocumentComponent> DocumentComponents { get; private set; } public DocumentComponent(string name) { Name = name; DocumentComponents = new List<IDocumentComponent>(); } public string GatherData() { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine(string.Format("<{0}>", Name)); foreach (var documentComponent in DocumentComponents) { documentComponent.GatherData(); stringBuilder.AppendLine(documentComponent.GatherData()); } stringBuilder.AppendLine(string.Format("</{0}>", Name)); return stringBuilder.ToString(); } public void AddComponent(IDocumentComponent documentComponent) { DocumentComponents.Add(documentComponent); } }
Gluing parts to be some kind of document:
var document = new DocumentComponent("ComposableDocument"); var headerDocumentSection = new HeaderDocumentComponent(); var body = new DocumentComponent("Body"); document.AddComponent(headerDocumentSection); document.AddComponent(body); var customerDocumentSection = new CustomerDocumentComponent(41); var orders = new DocumentComponent("Orders"); var order0 = new OrderDocumentComponent(0); var order1 = new OrderDocumentComponent(1); orders.AddComponent(order0); orders.AddComponent(order1); body.AddComponent(customerDocumentSection); body.AddComponent(orders); string gatheredData = document.GatherData(); Console.WriteLine(gatheredData);
Output is somewhat similar to XML. At least I tried to keep it similar.
<ComposableDocument>
<Header><MessageTime>8:47:23</MessageTime></Header><Body>
<Customer>Andriy Buday</Customer>
<Orders>
<Order>Kindle;Book1;Book2</Order>
<Order>Phone;Cable;Headset</Order>
</Orders>
</Body>
</ComposableDocument>
Also GoF guys suggest having Remove(Component) and GetChild(int) methods in your Component, so you might want to add them. Just don’t limit yourself with any kind of explanations. You might have some unique need.
code
more code
~~~~