henryjwr

See also: Other Geeks@INDC

September 2009 - Posts

State Design Pattern Maintain Flow of Algorithm Easily

In the book “Applying Domain-Driven Design and Patterns: With Examples in C# and .NET” by Jimmy Nielson he explain about State Design Pattern. He provide an example about state design pattern for Order transaction.

StateDiagram

This pattern is very nice, especially if you have a numerous transition flow in you problem. a beautiful about this pattern is eliminate hard coding of state transition and more flexible if you want to injected new state of it. combine with Strategy Design Pattern you could establish new state without brake the current implementation. imagine that you have already establishing a state flow in your code and suddenly the business process is change example from registered order could make invoice order and so on. With the helpfull of dependency injection and a little bit Strategy Pattern for your implementation you could achieve a better solution that doesn’t break OOD principle “Open/Close Principle” (A module should open for extension but closed for modification)

StatePatternCore

Above is 4GOF State Design Pattern.

   1: using System;
   2:  
   3: namespace ConsoleApplication1
   4: {
   5:     internal class SalesOrder
   6:     {
   7:         private IOrderState _currentState;
   8:         
   9:         public IOrderState OrderState
  10:         {
  11:             get { return _currentState; }
  12:             set { _currentState = value; }
  13:         }
  14:  
  15:         public string Id { get; set; }
  16:  
  17:         public SalesOrder(String id)
  18:         {
  19:             this.Id = id;
  20:             _currentState = new NewOrder(this);
  21:             
  22:         }
  23:  
  24:         public void RegisterOrder()
  25:         {
  26:             Console.WriteLine("Start Registering, Order Id: " + this.Id);
  27:             _currentState.Register();
  28:         }
  29:  
  30:         public void AddOrderLine()
  31:         {
  32:             Console.WriteLine("Start Add Order Line, Order Id: " + this.Id);
  33:             _currentState.AddOrderLine();
  34:         }
  35:  
  36:         public void Cancel()
  37:         {
  38:             Console.WriteLine("Start canceling, Order Id: " + this.Id);
  39:             _currentState.Cancel();
  40:         }
  41:     }
  42:     internal interface IOrderState
  43:     {
  44:         SalesOrder Order{ get; set;}
  45:         void AddOrderLine();
  46:         void Register();
  47:         void Ship();
  48:         void Cancel();
  49:         void Invoice();
  50:         void Grant();
  51:     }
  52:  
  53:  
  54:     internal class NewOrder : IOrderState 
  55:     {
  56:         public NewOrder():this(null){}
  57:  
  58:         public NewOrder(SalesOrder salesOrder)
  59:         {
  60:            this.Order = salesOrder;
  61:            Console.WriteLine("Order Id :" + Order.Id + " has taken order");
  62:         }
  63:  
  64:         #region Implementation of IOrderState
  65:  
  66:         public SalesOrder Order { get; set; }
  67:  
  68:         public void AddOrderLine()
  69:         {
  70:             Console.WriteLine("Order Id: " + Order.Id + " Do Add Order Line");
  71:             Order.OrderState = new NewOrder(Order);
  72:         }
  73:  
  74:         public void Register()
  75:         {
  76:             Console.WriteLine("Order Id: " + Order.Id + " Do Registering");
  77:             Order.OrderState = new Registered(Order);
  78:         }
  79:  
  80:         public void Ship()
  81:         {
  82:             throw new System.NotImplementedException();
  83:         }
  84:  
  85:         public void Cancel()
  86:         {
  87:             Console.WriteLine("Order Id: " + Order.Id + " Do cancel");
  88:             Order.OrderState = new Cancelled(Order);
  89:         }
  90:  
  91:         public void Invoice()
  92:         {
  93:             throw new System.NotImplementedException();
  94:         }
  95:  
  96:         public void Grant()
  97:         {
  98:             throw new System.NotImplementedException();
  99:         }
 100:  
 101:         #endregion
 102:     }
 103:  
 104:     internal class Registered : IOrderState
 105:     {
 106:         
 107:         public Registered(SalesOrder order)
 108:         {
 109:             this.Order = order;
 110:             Console.WriteLine("Order Id :" + Order.Id + " has been registered");
 111:         }
 112:  
 113:         #region Implementation of IOrderState
 114:  
 115:         public SalesOrder Order { get; set; }
 116:  
 117:         public void AddOrderLine()
 118:         {
 119:             Console.WriteLine("Order Id: " + Order.Id + " Do Add Order Line");
 120:             Order.OrderState = new NewOrder(Order);
 121:         }
 122:  
 123:         public void Register()
 124:         {
 125:             throw new System.NotImplementedException();
 126:         }
 127:  
 128:         public void Ship()
 129:         {
 130:             throw new System.NotImplementedException();
 131:         }
 132:  
 133:         public void Cancel()
 134:         {
 135:             Console.WriteLine("Order Id: " + Order.Id + " Do cancel");
 136:             Order.OrderState = new Cancelled(Order);
 137:         }
 138:  
 139:         public void Invoice()
 140:         {
 141:             throw new System.NotImplementedException();
 142:         }
 143:  
 144:         public void Grant()
 145:         {
 146:             throw new System.NotImplementedException();
 147:         }
 148:  
 149:         #endregion
 150:     }
 151:  
 152:     internal class Cancelled : IOrderState
 153:     {
 154:         public Cancelled(SalesOrder order)
 155:         {
 156:             
 157:             this.Order = order;
 158:             Console.WriteLine("Order Id: " + Order.Id + " Has been Cancelled");
 159:         }
 160:  
 161:         #region Implementation of IOrderState
 162:  
 163:         public SalesOrder Order { get; set; }
 164:  
 165:         public void AddOrderLine()
 166:         {
 167:             Console.WriteLine("Order Id " + Order.Id + " has been cancel please create new order");
 168:         }
 169:  
 170:         public void Register()
 171:         {
 172:             Console.WriteLine("Order Id " + Order.Id + " has been cancel please create new order");
 173:         }
 174:  
 175:         public void Ship()
 176:         {
 177:             Console.WriteLine("Order Id " + Order.Id + " has been cancel please create new order");
 178:         }
 179:  
 180:         public void Cancel()
 181:         {
 182:             Console.WriteLine("Order Id " + Order.Id + " has been cancel please create new order");
 183:         }
 184:  
 185:         public void Invoice()
 186:         {
 187:             Console.WriteLine("Order Id " + Order.Id + " has been cancel please create new order");
 188:         }
 189:  
 190:         public void Grant()
 191:         {
 192:             Console.WriteLine("Order Id " + Order.Id + " has been cancel please create new order");
 193:         }
 194:  
 195:         #endregion
 196:     }
 197:     
 198: }

The different betwen State Pattern and Strategy pattern are Strategy is more dynamic behaviour rather than State, so the state flow is determine by mapping behavior within | by its context. In other word State Pattern are use when we want to mapping already have state flow, on the other hand Strategy Pattern could manypulaterd the state of implementation using injection.

Share this post: | | | |
Creating a Custom Configuration Section in Application Configuration

When you creating a framework is definitely you must create some custom configuration to handle your application configuration. .NET provide Namespace that we could manipulated or create custom Configuration, “System.Configuration”. For basic usage we could create element and element collection, and wrap it in a configuration section. You could do more advance by Grouping the configuration Section using Configuration Section Group.

FullConfiguration

Before creating custom configuration, first we must design the configuration file content first. I have a sample it using to inject implementation class to an interface class using reflection.

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <configSections>
   4:     <section name="CustomMapping"
   5:              type="ConsoleApplication1.MappingSection, ConsoleApplication1"/>
   6:   </configSections>
   7:   <CustomMapping>
   8:     <MappingElements>
   9:       <MappingElement Interface ="IProduct" Implementation="ConsoleApplication1.Product" />
  10:     </MappingElements>
  11:   </CustomMapping>
  12: </configuration>

 

In configuration file above we create a custom section name = “CustomMapping” and the type that act as a section class is MappingSection. We define a MappingElement for the basic configuration element and MappingElements for the configuration Element Collection. In the Configuration Element we define two attribute “Interface” and Implementation. That it is we ready to create our custom configuration code.

1. Creating Configuration Element by inheriting “System.Configuration.ConfigurationElement” class.

   1: namespace ConsoleApplication1
   2: {
   3:     using System.Configuration;
   4:  
   5:     public class MappingElement : ConfigurationElement
   6:     {
   7:         [ConfigurationProperty("Interface", IsKey = true, IsRequired = true)]
   8:         public string AttributeOne
   9:         {
  10:             get { return (string)this["Interface"]; }
  11:             set { this["Interface"] = value; }
  12:         }
  13:  
  14:         [ConfigurationProperty("Implementation", IsKey = true, IsRequired = true)]
  15:         public string AttributeTwo
  16:         {
  17:             get { return (string) this["Implementation"]; }
  18:             set { this["Implementation"] = value;}
  19:         }
  20:  
  21:     }
  22: }

In this class we define a property that will exist in our configuration as an Attribute. Each property must state with .NET Attribute “System.Configuration.ConfigurationPropertyAttribute”. this class takes Name property for the identity | name of the attribute. and other optional property like whether the attribute is a key, must exist etc. When you have many of attribute that we want to specify you could use a class constant to declare all the name.

2. Creating Configuration Element Collection by inheriting “System.Configuration.ConfigurationElementCollection” class.

   1: namespace ConsoleApplication1
   2: {
   3:     using System.Configuration;
   4:  
   5:     public class MappingElementCollection : ConfigurationElementCollection
   6:     {
   7:  
   8:         protected override ConfigurationElement CreateNewElement()
   9:         {
  10:             return new MappingElement();
  11:         }
  12:  
  13:         protected override object GetElementKey(ConfigurationElement element)
  14:         {
  15:             return ((MappingElement)element).AttributeOne;
  16:         }
  17:  
  18:         protected override string ElementName
  19:         {
  20:             get
  21:             {
  22:                 return "MappingElement";
  23:             }
  24:         }
  25:  
  26:         public override ConfigurationElementCollectionType CollectionType
  27:         {
  28:             get
  29:             {
  30:                 return ConfigurationElementCollectionType.BasicMap;
  31:             }
  32:         }
  33:  
  34:         public MappingElement this[int index]
  35:         {
  36:             get { return this.BaseGet(index) as MappingElement; }
  37:             set {
  38:                 if (this.BaseGet(index) != null)
  39:                 {
  40:                     this.BaseRemoveAt(index);
  41:                 }
  42:                 this.BaseAdd(index, value);
  43:             }
  44:         }
  45:  
  46:         public new MappingElement this[string interfaceShortName]
  47:         {
  48:             get { return this.BaseGet(interfaceShortName) as MappingElement; }
  49:         }
  50:     }
  51:     
  52: }

This class will act as a collection to our Element. First we override CreateNewElement() method, this behavior is to set what element that will be create for this collection in this case we return our element class that have been create before. Next we override GetElementKey() method, this behavior is to retrieve what is the key for the element. This behavior is use when we retrieve element by it is using BaseGet() method. we also override ElementName is for setting the tag name of Element in XML configuration file. Overriding CollectionType to set the type we want to use, in this case we use BasicMap type. When use BasicType the child element child could not override property of its parent property.

The last two method is very important. This Indexer property is to manipulating element collection to retrieve child element by its index or by name. first Property is act like to add and retrieve collection by its index. and second is shadowing base class indexer and use name index to retrive specific element.

3. Finally we have to create section class that to handle Section for our custom configuration file. this could achieve by inheriting “System.Configuration.ConfigurationSection” class.

   1: namespace ConsoleApplication1
   2: {
   3:     using System.Configuration;
   4:  
   5:     public class MappingSection : ConfigurationSection
   6:     {
   7:         [ConfigurationProperty("MappingElements",IsDefaultCollection = true)]
   8:         public MappingElementCollection MappingElements
   9:         {
  10:             get { return (MappingElementCollection) base["MappingElements"]; }
  11:         }
  12:     }
  13: }

Basically this class just wrap our element collection. so for simple usage we define a property that return our element collection type. define attribute ConfigurationProperty setting the Element Collection name, and set wheter is default collection or not.

That it is, we currently finished creating custom configuration file.

let see how to use our custom configuration file.

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <configSections>
   4:     <section name="CustomMapping"
   5:              type="ConsoleApplication1.MappingSection, ConsoleApplication1"/>
   6:   </configSections>
   7:   <CustomMapping>
   8:     <MappingElements>
   9:       <MappingElement Interface ="IProduct" Implementation="ConsoleApplication1.Product" />
  10:     </MappingElements>
  11:   </CustomMapping>
  12: </configuration>
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Configuration;
   6:  
   7: namespace ConsoleApplication1
   8: {
   9:     internal interface IProduct
  10:     {
  11:         string ProductName { get; set; }
  12:     }
  13:  
  14:     internal class Product : IProduct
  15:     {
  16:         private string _product;
  17:         #region IProduct Members
  18:  
  19:         public string ProductName
  20:         {
  21:             get
  22:             {
  23:                 if (_product == "" || _product == null)
  24:                 {
  25:                     _product = "Pepsodent";
  26:                 }
  27:                 return _product;
  28:             }
  29:             set
  30:             {
  31:                 _product = value;
  32:             }
  33:         }
  34:  
  35:         #endregion
  36:     }
  37:  
  38:     class Program
  39:     {
  40:         static void Main(string[] args)
  41:         {
  42:             MappingSection section = ConfigurationManager.GetSection("CustomMapping") as MappingSection;
  43:             Type type = Type.GetType(section.MappingElements[typeof (IProduct).Name].AttributeTwo);
  44:  
  45:             IProduct product = Activator.CreateInstance(type) as IProduct;
  46:             Console.WriteLine(product.ProductName);
  47:         }
  48:     }
  49: }

First we get the section using System.Configuration.ConfigurationManager.GetSection() it takes the name of xml tag name in configuration in this case CustomMapping. when we have reference to section we could use property that we define in the class (MappingElements) that return element collection. we could use int indexer or name indexer to retrive element. in this case we use name indexer and retrieve property AttibuteTwo to retrive the implementation of the interface we want to create the instance (ConsoleApplication1.Product).

Happy Programming

Share this post: | | | |
Posted: Sep 08 2009, 11:19 PM by henryjwr | with 1 comment(s)
Filed under: