Command-Observer Pattern Implementation (continued)
The three observer-class implementations in this example, PartsDept, TransportDept, and SalesDept, maintain an internal Hashtable that holds a count of the number of each car model built, and stores it in the user's session, in exactly the same way as the Publish-Subscribe pattern example. These classes also expose this Hashtable as a property so that client applications can access it.
The main differences between the Publish-Subscribe and Command-Observer examples are that the observer classes in the Command-Observer example implement the IObserver interface, and therefore each must expose an Update
method is the equivalent of the event handler in the Publish-Subscribe example. It casts the received object (passed to the method as a parameter instead of an event argument instance) into an instance of the ProductionLine class, and extracts any property values it requires. Then the method can update the Hashtable and store it back in the user's session. Here's the Update method implementation in the PartsDept observer class:
public void Update(Object subject)
// called by ObserverHelper.Notify method. Do any
// work required in Observer class here. Parameter is
// the instance of the subject class, so code can query
// its properties if required
String carName = (subject as ProductionLine).
// in this example, just increment count of parts used
partsUsed[carName] = (Int32)partsUsed[carName] + 1;
// save count in session
HttpContext.Current.Session[SESSION_KEY_NAME] = partsUsed;
You can find the client code that demonstrates the Command-Observer pattern in the ASPX page named TransferPage5.aspx
. When you click the "Build Car" button on that page, the page code creates instances of the main ProductionLine class, and the three observer classes PartsDept, TransportDept, and SalesDept. Then, depending on the settings of the three checkboxes, it subscribes these observersthis time by calling the AddObserver
method of the helper class associated with the current ProductionLine instance.
Then the code calls the BuildNewMotorCar
method, specifying the model name selected in the drop-down list in the ASPX page. This notifies each subscribed observer, and the code continues by displaying the resulting values from the Hashtable of each observer using the same ShowAllCarsCount
method as the previous example:
protected void btn_Build_Click(object sender, EventArgs e)
// create instance of subject class that contains
// the method that will notify subscribed observers
ProductionLine pLine = new ProductionLine();
// create instances of classes that will observe the subject
//(the ProductionLine class) and get notified when required.
// any class that implements IObserver can be used here
PartsDept parts = new PartsDept();
TransportDept transport = new TransportDept();
SalesDept sales = new SalesDept();
// subscribe the observers according to settings in the page
// call the main method of the subject class
// to do the actual work required, specifying
// any properties required (in this example,
// just the name of the car to build).
// display counter values from observers to show that they
// were notified by the ProductionLine main routine
lblResults.Text += "<b>Cars to deliver</b>: "
lblResults.Text += "<b>Cars available to sell</b>: " +
lblResults.Text += "<b>Parts to order</b>: " +
|Figure 6. Command-Observer Pattern: Here's the sample application showing how it uses the Command-Observer pattern.|
shows result of the Command-Observer pattern example after building a few cars and changing the settings in the three checkboxes so that only some observers subscribe to the notification each time.
Summing Up ASP.NET Design Patterns
|Author's Note: You can open this page by selecting either "Command-Observer" or "TransferPage5.aspx" in the drop-down list at the bottom of the Default.aspx page.
From the various patterns discussed in this article series (see the Related References for links to the previous articles), it is possible to draw the following conclusions:
- The MVP and the various Controller patterns are useful, but firing update events from the Model usually is not.
- The Page Controller and Front Controller patterns allow for custom use-case behavior by showing different views or activating different presenters. Front Controller can make use of the Intercepting Filter pattern.
- The Repository pattern is useful for virtualization of source data.
- The Singleton pattern is useful for reducing the need for multiple instances.
- The Service Agent and Proxy patterns are ideal for interacting with remote services.
- The Provider pattern is useful for accessing various types of data sources.
- The Adapter pattern is useful for extending ASP.NET controls.
- The Factory, Builder, Injection, Observer, and Command patterns are less useful, more complex, and can be difficult to implement.
- Event-driven patterns such as the Publish-Subscribe pattern that rely on subscribers having a long lifetime are difficult to implement due to the nature of ASP.NET, and are probably not viable. However, the Publish-Subscribe pattern is useful if all subscribes are instantiated within the current page lifetime.
- The composite event-free Command-Observer pattern approach is useful for removing dependencies between classes.