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