Friday, July 11, 2008

Bridge Pattern vs Strategy Pattern

Short Form: both patterns are uses of inheritance to add flexibility. In both patterns, one class (the Container) has a reference to an Interface or base class, which is obviously intended to be subclassed.

In the Bridge pattern, the Container serves as an Adapter to the Interface, allowing Container's public interface to vary independently of the implementation in the subclasses. Bridge is a pattern that makes it easier to maintain code and add features.

In contrast, the Container's public interface isn't relevant to the Strategy pattern. The idea behind Strategy is to add flexibility to a class via the use of a contained object, instead of putting code directly in the Container and using a switch statement or whatever.

See also Builder Pattern vs Factory Pattern or Aggregation vs Composition.

--

I asked an interviewee about the Strategy Pattern yesterday, and it got me thinking about how best to explain the concept to someone. I'm of the belief that if you can't explain a concept then you don't really know it. There are a lot of concepts that one might have a fuzzy grasp of, but there's a wide gulf between that fuzzy grasp and being able to explain a concept to someone else. Explaining stuff is a great way to learn. That's one of the main reasons why I blog. :)

A pattern is a way of helping you abstract what your code is doing. It's a learning tool. We use a pattern name so that we can quickly explain what we're doing to others and so we can quickly implement new code. If I tell you that I'm using a Bridge in this one piece of code, and you know what a Bridge is, then I don't have to go through the trouble of explaining what all is going on. The word "Bridge" captures all of that info. If you only have a fuzzy grasp of the concept then we haven't really communicated. I said "bridge" but you heard "some sort of abstract connection thingy."

Patterns also help us categorize past experiences. I've implemented the Strategy pattern frequently and there's a few things I like to do the same way each time, like using an enum to specify which strategy to use. Following an existing pattern means not having to make up something from whole cloth.

The Bridge and Strategy patterns are structurally the same thing. They differ in intent. They're also similar to the State pattern and sometimes confused with the Template Method pattern, so I'll go over all four. Keep in mind that the purpose of using jargon is to communicate not just the fact that you're using inheritance somewhere, but why you're using it, and how the code is making use of it.
A Bridge is a pattern that allows you to vary the interface and implementation separately.

A Strategy is the parameterized variation of behavior.

The State pattern allows the dynamic variation of behavior.

A Template Method allows the variation of implementation without changing the algorithm.
You might be thinking, "Huh?"

As I've said before, the best way to explain a concept is by using a few examples, including at least one negative example (to make sure you've communicated the limits of the concept). So let me give some examples of common usage.

A Strategy allows you to swap in different behaviors by using a base class or Interface. You'll have at least four classes in this model: the Container, the Base Class, and two (or more) Subclasses. Say you've got a game with creatures that do different behaviors, such as Guard or Patrol or Hunt. Your AI class for the creature (the Container) contains a base class pointer (the Interface), which is an instance of one of the various Subclasses. You could have just had a switch statement somewhere in your AI class; that would not be a Strategy. Moving the 'joint' into a new class and using various subclasses to implement the behavior is the Strategy pattern.

Or maybe you have a button in your UI, but that button could be drawn using a texture or by rendering text over a standard rounded-rectangle. Instead of implementing two different Button classes, you could create a new ButtonRenderer class to encapsulate how you draw the control. The Button class (the Container) contains a pointer to a ButtonRenderer (the Interface), which will be either TextureButtonRenderer or TextButtonRenderer.

Strategy example:
class Button
{
private ButtonRenderer _renderer;
public Button( ButtonTypeEnum visualAppearance )
{
if (visualAppearance==ButtonTypeEnum.TexturedButton)
_renderer = TexturedButtonRenderer;
else
_renderer = TextButtonRenderer;
}
...
}
A Bridge is when you want to vary the implementation and interface separately. Say you've got a data access layer. The layer talks to an underlying database; you might want to change the type of database that you connect to. This could range from changing the connection string (to switch from a development DB to the production DB) to changing the database type (from SQL to Access to a stored XML file). But this layer also exposes an interface to the next higher layer (the business logic layer). A data access layer is, essentially, a Bridge: it separates the public interface of a class (Business Logic -> DAL) from its implementation (DAL -> Database).

One can think of a Bridge is a combination of a Proxy (or Adapter) and a Strategy. Instead of just coding one base class and its subclasses, Bridge adds another object into the picture. This extra class provides the external interface, and maps that interface to the base class's interface. You can vary the interface (ie the extra class's public methods) separately from the implementation (ie the various subclasses).

You say "Strategy" when you want to vary behavior, and you do so not by writing different objects but by introducing a class heirarchy. You say "Bridge" when you expect that you will vary both the interface and the implementation. In both cases you're providing flexibility for a changing implementation; in a Bridge, you're also expecting the interface to change.

A Strategy is when one type of object implements some part of its behavior using another class. For example, a Button implements rendering (but not click-processing or message-sending) using a new class. A Bridge implies that you could have just used that class directly somewhere up the chain, but that you want to add in an Adapter or Proxy on top. The interface that a Bridge object exposes is usually similar to the base class; in a Strategy, the public interface of the container object is often completely different than the contained base class. A Strategy says that you are implementing part of the container's behavior using the base class.

The State pattern is similar to Strategy. Typically, a Strategy pattern means that you set an object's behavior at construction, like the Button example above. Buttons don't change from one appearance to another in the middle of a game! The AI example, though, is more like the State pattern: not only have you provided flexibility by adding a new base class and stuffing variation into new classes instead of using a switch statement or if statement, but you'll be changing out which subclass you use fairly frequently. "State" implies a Strategy that changes frequently over an object's lifetime. "State" also implies that you're trying to encapsulate some complex, dynamic portion of an object's behavior into a new class, where "Strategy" implies that, when the Container object is constructed, that its creator will tell the Container what approach to take for its entire lifetime.

The Template Method is really not similar to these, but sometimes people confuse it with one of the others. Say you've got an object's script in an XML file; in-game, you turn each one of the "commands" in the XML into a call into some other class. Say the XML script includes commands like Attack, Move, Find Target, Use Bandaid, etc. Different creatures could use the same script to do their thing, but they might do it in different ways -- Attack could be performed by casting Magic Missile, or firing a bow, or by swinging an axe -- the script is then a Template Method. It's an algorithm that can be implemented in different ways. A Template Method can be considered a sequence of different Strategy choices, and is often implemented that way.

Similar Posts:
Builder Pattern vs Factory Pattern
Aggregation vs Composition

See Also:
Bridge at Wikipedia or c2
Strategy at Wikipedia or c2
State at Wikipedia or c2
Adapter at Wikipedia or c2
Proxy at Wikipedia or c2

1 comment:

Meer said...

Thanks.. very nice explanation!