A Quick Example

Let's take a simple example: Say we want to start allowing complex pricing to be used for objects in our earlier Product Configuration example (see page 45). Specifically, I would like to support three pricing alternatives: a fixed price, a price computed by summing the subparts, and a real-time price that consults an external database for the price. If you recall, our final high-level solution looked liked that in Figure 8.1.

Figure 8.1. Product Configuration example


It should be fairly straightforward to understand that the pricing calculation needs to affect only the part hierarchy. But how do we provide a way in which to allow the flexibility for pricing that we envision is necessary? When we look at the existing patterns we want to use, the questions that arise are is the price an algorithm used by a part, or can a part have one of many pricing states? This will help decide if a Strategy pattern or State pattern [Gam, 95] is more appropriate. We looked at the State pattern earlier (see State on page 50); the Strategy pattern is similar.

Strategy Pattern

Intent

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Varies

Varies includes an algorithm or a family of algorithms.

Structure

Figure 8.2 illustrates the Strategy structure.

Figure 8.2. Strategy structure


Comments

This pattern is very similar to the State pattern in structure, but conceptually both have a very different intent. The key determination of whether behavior is driven by the state or the set of algorithms may seem arbitrary, but it needs to be considered. Normally, State is internal to the object, and strategies can be external, but this is not a hard and fast rule.


I have found it useful to implement a Strategy pattern for common error handling capability in products. Often when a project is divided among multiple developers, different mechanisms for displaying errors evolve. This can make things very difficult later when the various parts are integrated, by providing a common interface such as



This error Handler can be requested from a factory method when it is required or passed to the appropriate routines at construction.

Then at run time we can provide different mechanisms such as a windows-based mechanism using MsgBox, a console-based display using text output, a file-based mechanism, or even SNMP alerts that tools can use to detect these problems. Any combination of these mechanisms can be chosen (at run time as well) without impacting any of the code already in place. By deciding on the use of the errorHandling interface up front, we can postpone the final decisions as well.

Either of these two patterns can be successfully applied in this situation. We need to weigh the trade-offs. In my experience, part of this determination is whether the pricing rules exist outside of the part (in which case a Strategy pattern is more appropriate) or inside of the part (in which case a State pattern is more appropriate). Based on the decision of the earlier view to have a fixed or composite price be a mode of the CompositePart, I will use a State pattern for consistency. I will make the state objects lightweight by passing the part information as a external variable on the calculation so that they can be shared. A Flyweight pattern [Gam, 95] that would allow sharing of lightweight objects can be used here, but because the object is now totally stateless, we do not receive any real benefit by introducing object pooling. Figure 8.3 illustrates the new pricing mode.

Figure 8.3. The new pricing mode


In order to make the selection of Pricing mode completely dynamic, we add a selection method to Part. As always, we avoid storing any data members in the interface or abstract class and put the storage into the intermediary class BasicPart. Now we can remove the flag and getPrice() routine used at the CompositePart because the BasicPart object can now fully handle this calculation. Figure 8.4 shows the updated pricing framework.

Figure 8.4. The updated pricing framework


The only remaining area where we need to modify the system is the point at which the decision to use the appropriate pricing mode is made, the builder. We can add a simple PricingMode selection capability here and make the builder responsible for creating the appropriate pricing class. This means that additional pricing modes can be added, and the only point of impact going forward will be the builder. In effect, we have now fully provided the hinge points for infinite pricing variances. Figure 8.5 illustrates the updated part builder.

Figure 8.5. The updated PartBuilder


Our extended system is illustrated in Figure 8.6.

Figure 8.6. The product configuration system with pricing modes


Note that we can now put many parallel teams to work implementing the different pricing modes as well as each part of our system. In addition, it should be easy to see that by adding this functionality the code complexity has not been increased (although design complexity has). In fact, it could be argued that this is even a simpler system to code and test after this reorganization.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.102.225