You are currently viewing the BOOK: Professional ASP.NET Design Patterns section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, win occasional prizes given to our best members, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
let me say first of all that I find this book magnificent. Having a bit of a bore-out at work, this book gives me more fun with coding than I have had in a long time. I'm only just starting with it (chapter 5 now), but can see its applicability already.
But to start with my actual question... is it me, or is the difference between State pattern and Strategy pattern really thin?
I'm trying to use this for a simple purchase approval processing webform and lean towards the strategy pattern to use.. (Depending on whether the request is already in process with a supplier (hence its state) concretestrategy A or B must be used ...)
Although it is the state of the request that governs the actual method, it feels more natural to use the strategy pattern. Looking at the UML they are almost alike... so I tend to believe there is no harm to use this. Or am I missing some big difference in the two patterns here?
Location: Southsea, Portsmouth, Hampshire, United Kingdom.
Posts: 94
Thanks: 11
Thanked 16 Times in 15 Posts
Hi disel2010,
Thanks for reading the book!
Yes the two patterns do look very similar this is because they are both employing polymorphism at their core. Let's take a look at their definitions:
The state pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
The strategy pattern defines a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
So you can see that they are concerned with two very different things.
Ok lets take a look at your problem..
Quote:
I'm trying to use this for a simple purchase approval processing webform and lean towards the strategy pattern to use.. (Depending on whether the request is already in process with a supplier (hence its state) concretestrategy A or B must be used ...)
I am not sure of the intricacies of your problems but lets assume that the purchase order can be in the following states:
- Open
- Submitted
- Approved
- Rejected
Lets also assume that we need to alert people when the purchase order state changes. Some people want to be alerted by text messages, others by email. In order to notify interested parties we need to apply the correct notification strategy. Hopefully you can see from the sentance above where the patterns fit. Here is some code to see it all in action...
Code:
public class PurchaseOrder
{
private IPurchaseOrderState _internal_state;
public PurchaseOrder() : this(new PurchaseOrderOpenState())
{ }
public PurchaseOrder(IPurchaseOrderState initial_state)
{
_internal_state = initial_state;
}
public bool can_add_item()
{
return _internal_state.can_add_item();
}
public void add(Item item_to_purchase)
{
if (can_add_item())
{
// update internal storage...
}
else
throw new ApplicationException("You can't do this...");
}
public void submit()
{
_internal_state.submit();
}
public void approve()
{
_internal_state.approve();
}
public void change_state_to(IPurchaseOrderState new_state)
{
_internal_state = new_state;
}
public bool is_valid_for_submission()
{
// check all is ok....
return true;
}
public Person approver { get; set; }
public Person originator { get; set; }
public void notify_approver_with(string message)
{
approver.send(message);
}
public void notify_originator_with(string message)
{
originator.send(message);
}
}
public class Person
{
// This is the strategy
public INotificationChanncel notification_channel { get; set; }
public void send(string message)
{
notification_channel.send(message);
}
}
public interface INotificationChanncel
{
void send(string message);
}
public class EmailNotificationChanncel : INotificationChanncel
{
private readonly EmailAddress _emailAddress;
public EmailNotificationChanncel(EmailAddress email_address)
{
_emailAddress = email_address;
}
public void send(string message)
{
// email...
}
}
public class PurchaseOrderOpenState : IPurchaseOrderState
{
public bool can_add_item()
{
return true;
}
public void submit(PurchaseOrder purchase_order)
{
if (purchase_order.is_valid_for_submission())
{
purchase_order.notify_approver_with("PO is now submitted");
purchase_order.change_state_to(new PurchaseOrderSubmittedState());
}
}
public void approve(PurchaseOrder purchase_order)
{
// need to submit first
throw new ApplicationException("You need to a submit an application before approval.");
}
}
public class PurchaseOrderSubmittedState : IPurchaseOrderState
{
public bool can_add_item()
{
return false;
}
public void submit(PurchaseOrder purchase_order)
{
// need to submit first
throw new ApplicationException("This PO has already been submitted.");
}
public void approve(PurchaseOrder purchase_order)
{
purchase_order.notify_originator_with("PO is now approved"));
purchase_order.change_state_to(new PurchaseOrderSubmittedState());
}
}
public interface IPurchaseOrderState
{
bool can_add_item();
void submit(PurchaseOrder purchase_order);
void approve(PurchaseOrder purchase_order);
}
Hopefully you can see the difference. If I haven't answered your question please reply.
Cheers
Scott
The Following 2 Users Say Thank You to elbandit For This Useful Post:
Scott,
This is a great book! Wish I had bought it sooner! I have a quick question regarding the following scenario:
a patient's visit to an outpatient clinic can be in any of the following states:
pending, kept, cancelled.
if the visit is kept, a therapist treats the patient and enters charge codes for the services rendered to the patient; so, there is a new state (charge entry state) than can be partially entered or complete.
when charges are complete, the visit and the charges are billed so you could say that a visit can be billed or not or put on hold.
The current system I am maintaining is using one property where all the above statuses are mixed in. Should I create 3 properties, one for the visit status, one for charge entry status and one for billing status?
Please advise.
Thanks,
Huambo