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.
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)
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.
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.
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
If you crazy enough combine it with Google Wave you will find that you in the middle of new world .....HTML 5...
4 supporting Line comunication you could set simple implementation of http://asterisk.org/ (Asterisk is the world's leading open source PBXi,
telephony engine, and telephony applications toolkit. Offering
flexibility unheard of in the world of proprietary communications,
Asterisk empowers developers and integrators to create advanced
communication solutions...for free)
Please Checkout this http://code.google.com/p/queplix/
....Happy ....more happy everyday.....
These are the feature ....(Great man...)
QueCore
– Provides core operational services for the QueWeb system. QueCore
does not contain any customer-specific customizations, business logic
or presentation elements. As such, it contains Java classes and
architecture elements to enable database connectivity, provides
QueWeb’s basic structural components, and includes all required
standard Java libraries and 3rd party components for the
integration with other systems. QueCore utilizes Google’s© Web Toolkit
(GWT) technology and is shared across the QueWeb editions. Small and
medium size companies can now rely on the same platform with
enterprises that successfully run QueWeb.
QueTask – Auxiliary QueCore
process, which provides execution of all time-dependent system
processes. This module allows scheduling and execution of reports,
notifications, escalations and external processes (such as SQL scripts
or Stored Procedures for data import/export, UNIX shell scripts or MS
Windows batch jobs) that require execution upon certain time or
conditions. QueTask is responsible for capturing logs from the external
processes as well as passing variables to tasks from the QueWeb
database.
QueScheduler – Visual Interface
for the QueTask component; it allows maintaining the schedules for the
QueTask tasks. By default it is available to the system administrator,
permits monitoring of tasks execution, defines variables to be passed,
maintains distribution lists for reports and notifications, etc.
QueScheduler also runs all internal time-dependent functions in
QueWeb, such as escalation triggering, email polling, reports
execution, etc.
Email Routing – This module
provides a facility to track incoming and outgoing email
communications. It can be used in addition to any standard email
software, i.e. Outlook or Lotus Notes. QueWeb Email module allows
tracking and creating service requests, cases and interactions by
monitoring incoming email for multiple accounts. The email can then be
routed to the appropriate individual or a workgroup, based on the
routing rules. Standard routing rules are keyword-based and can be
triggered depending on the sender, product and category, type of
problem, agent availability or possession of a certain skill or based
on the previous history for the customer. QueWeb Email boasts
additional powerful features such as support for multiple languages,
HTML formatting, text templates, spell checking, attachments parsing,
auto-replies, spam filters and account size control for individual
users. QueWeb can be integrated with Exchange or Notes servers directly
through IMAP, POP3 or SMTP protocols for a real-time synchronization of
email.
Ad-Hoc Report Writer – Ad-hoc
Report Writer allows users to create and distribute their own reports
on the predefined schedule or in real time. The reports are created
simply by selecting a combination of the GUI field labels on any of the
QueWeb screens. Users can specify constrains (parameters) for the
report by populating the search constraints in the same user interface
which they use to search in QueWeb; thus there is no additional
training required to utilize ad-hoc reporting features in QueWeb.
Ad-Hoc Report Writer will automatically connect all data objects used
in the report and create optimum joints in order to produce complex
queries, grouping and various sorting of the data as requested by the
user. Users can print, save and export reports to MS Office© programs
or create an email distribution list.
My QueWeb – By default all users
first see this module upon login. My QueWeb is a collection of
information screens which are relevant to the current user and provide
at-a-glance snapshot of the current work queue and tasks. My QueWeb
consists of My Queue, which combines all incoming Emails, Alerts,
Escalations and Notifications as well as Action requests and system
messages. It is a place from which many standard workflow processes
start. My QueWeb also contains graphical dashboards; depending on the
user’s role (Manager, Support Agent, IT Help Desk, etc.) they provide a
graphical picture of many vital activities that are relevant to the
particular user’s role.
Interaction and Case Portal–
All Interactions entered by QueWeb agents are captured in the system,
regardless of the communication channel: email, phone, chat, customer
portal, and fax. Agents have an ability to quickly resolve the issue
using Knowledge Base; otherwise they can further research or
escalate/reassign the issue by creating a Case record from the
Interaction and maintain a follow up with the Customer. A single
interaction can contain several issues and each can be tracked
separately. Customers have access to their previous Cases and
Interactions through the Customer Portal.
Case Management – Allows the
system administrator or Customer Support Agents to create and perform
various maintenance activities with Cases. These include: archiving
based on the predefined time expiration or conditions, time and
statistical metrics maintenance, workflow propagation, user
participation in activities and Case loads, notifications and
escalations based on the predefined conditions, etc, designating data
elements for the Audit control. Workflow Management module is designed
to facilitate complex business processes around Cases to ensure the
timely and effective resolution and creating an overall satisfying
customer experience.
Knowledge Management – This module
allows the system administrator to manage the Knowledge base options.
The Knowledge base management consists of defining options for
Solutions, their usage in Cases, Solution expiration time, Solution
user roles definitions (authoring, reviewing, publishing, archiving,
and removal). Solution publishing workflow goes through Draft, Review,
Internal, Published and Expired modes while the system monitors
corresponding dates, solutions which are not used and notifying
Solution Authors to review those that are expired. Solutions can also
be published as FAQs for the Customers’ use on the Customer Portal.
Customers also have ability to troubleshoot issues by accessing allowed
resolutions, which pertain to their products.
Product Management – Allows creating and maintaining various levels of the Product and Product Components.
Customer Management – Provides
maintenance of Customer and Organizational records, as well as their
relationships with the company’s employees. Customers can be
distinguished as external or internal to the Company. Customers can
edit their personal records through the Customer Portal.
Email Management – This module
allows processing incoming and outgoing email communications through
email routing rules. These rules are used to create Cases from incoming
emails and to determine Case assignments to the appropriate employees
with specific skills or other criteria, i.e. assign to the Agent who
last handled this Customer, or has specific experience with the
Customer’s Product. This module also allows management of the Inbox and
Outbox for each user (size, frequency of polling, MS Exchange accounts,
etc). QueWeb Email module can be integrated with Exchange or other
Groupware Servers using included connector, IMAP, POP or SMTP
protocols.
Logs Management – Monitors and
allows browsing for the system and error logs. Several levels of
verboseness can be set. Using this module, the system administrator can
configure Email Notifications or Alerts when predefined events or
system errors occur.
User Management – The system
administrator can utilize this module to create and maintain User
accounts and Customer accounts for the Customer Portal access. Login
IDs and encrypted passwords can also be set or reset. Single sign-on
feature for Microsoft Windows Server is pre-built in QueWeb with LDAP
look up and authentication.
Access Control Module – QueWeb
leverages a sophisticated application-driven permissions access
mechanism: All users are organized in Work Groups, which can be
associated with appropriate User Roles (i.e. Administrator, Power User,
Solution Approver, Analyst, Manager, etc.) Based on these associations,
the system provides several levels of access: No Access, Read Only,
Write, Delete to any modular component of the system: Focus, Tab, Form
or even data element (data field).
Escalations and Notifications Module
– The QueWeb system enforces compliance with dynamic workflow processes
by using Escalations and Notifications mechanism. Notifications can be
email, page or broadcast messages, which occur based on predefined
workflow conditions (conditions can be customized to reflect specific
workflows). Escalations are time-dependent, and can be triggered upon
meeting predefined logical conditions and fire after a set time period.
For example, escalation conditions can be based on the status of the
Case: Send an email to the Case Analyst if the Case is Not Closed within 30 minutes after its creation time and, as a second-tier escalation, escalate the Case to the Manager if a Case is Not Updated within 1 hour.
Auditing Module – This module
allows designating certain fields to be audited. Users with proper
permissions can view the history of all changes for the Audited record
with timestamp, user name, old and new values.
System Properties Module –the
System Properties module allows dynamic management of the System
Properties throughout the application. The customer’s system
administrator can change any variables using this module. The System
Properties tab also contains Out Of the Box all necessary variables to
start working in the system after the initial installation: the name of
the SMTP server, default email account, locks timeout and other global
and system settings.
Normal
0
false
false
false
IN
X-NONE
X-NONE
MicrosoftInternetExplorer4
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
line-height:115%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"Times New Roman";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;}
Hi Comrad,
This question is 4 everybody who enjoy live behind microsoft infrastructure.
Also 4 everybody who playing around with Mr MIC background. I didn't knew
about bussiness i just seek about tech and solution.
Some people has mention that there is a dead road map and more slower
progress to anothers that happen on microsoft platform. Since the glory of XP
and 2000 platforms threre no other heroic moment that bring full enjoying live
within Microsoft way. Many product that has been lunching but is very difficult
4 other to follow the right track. we didn't talk about enchament only in
enterprise we also talk about stability, and future adoption.I don't want to
compare it with other Microsoft competitor. Everyone of them have their own
characteristics.
When i talk with several of my comrades that live outside Microsoft
boundary, they will show their grow of satisfaction, building from small
adaption to larger enterprise. They will takl about thousand resources that already
setting up.They sometime also seek other solution but most of them just to
justify that their platform already supporting them not to move arround.
IT Product is like glasses its fragile. They often obsolate frequently. and
everyone could fill it with anything. Microsoft often release a glowing
glasses. Everybody are enjoy to see it 4 the begining. Hoping that it would be
the long lasting artifact that could bring them to a party of heaven. But there
always but in global industry since Mr G aka Google comes to joining the party.
Mr G paradigma is only to Served their users. you dont have to worry about
paying your but to sit down on fire. But Mr G always talk future are as simple
as right now. you dont have to worry about replacing your "car" while
you want to increase the speed.
As a person i dont want to see Mr Mic to die slow or walking to the grave
yard also. I want it Mr Mic to more Stable and give a glass that not always
glowing but also full with water of enjoy, everybody who drink it become more
confident that this water like a tonic give us more energy to stand among the
crowd.
Simple as a sugestion did Windows 7 and it supported family could do that, or
is just a begining of a "Dead Ceremony"? .....