Why is the Strategy Pattern better than a case statement

Why is the Strategy Pattern better than a case statement

Post by jmedfor » Mon, 15 Feb 1999 04:00:00



One of the benefits that the GOF list for the Strategy Pattern is that
you can use it to replace case statements or conditionals.  Why is this
better?  I can see the advantage when each algorithm needs to create and
save information peculiar to that algorithm, and especially where the
choice of algorithm is made rarely. Am I thinking too much in terms of
efficiency and not enough in terms of clarity of design?
 
 
 

Why is the Strategy Pattern better than a case statement

Post by John Burto » Mon, 15 Feb 1999 04:00:00



>One of the benefits that the GOF list for the Strategy Pattern is that
>you can use it to replace case statements or conditionals.  Why is this
>better?  I can see the advantage when each algorithm needs to create and
>save information peculiar to that algorithm, and especially where the
>choice of algorithm is made rarely. Am I thinking too much in terms of
>efficiency and not enough in terms of clarity of design?

You might have a single object representing a "stragegy" used in several
place in your software maybe by calling different member functions.
If you add another stragegy you don't need to change any existing code
but if you used switch statements you'd need to go through your code finding
and changing all of them.

This is a good thing, it reduces the amount of coupling between the code
making use of the algorithms and the algorithms themselves.

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Nikolai Pretzel » Tue, 16 Feb 1999 04:00:00


Quote:>>>>>>>>>>>>>>>>>> Ursprngliche Nachricht <<<<<<<<<<<<<<<<<<


Thema Why is the Strategy Pattern better than a case statement:

Quote:> One of the benefits that the GOF list for the Strategy Pattern is that
> you can use it to replace case statements or conditionals.  Why is
this
> better?  I can see the advantage when each algorithm needs to create
and
> save information peculiar to that algorithm, and especially where the
> choice of algorithm is made rarely. Am I thinking too much in terms of
> efficiency and not enough in terms of clarity of design?

Besides the improved handling and changeability of code - as for
Efficiency: A virtual function call is (AFAIK) faster than an if and
definitely faster than a switch.

But if you need to change the strategy almost each time you use it
(you seemed to suppose such a case in the above quote), there is
indeed a little overhead. Perhaps the strategy pattern needs an
adjustment for that case.

That leads to: Probably in most cases the pattern I find valuable
needs
some adjustments to match my actual circumstances.

  Nikolai

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Tim Ottinge » Tue, 16 Feb 1999 04:00:00



> Why is the Strategy Pattern better than a case statement:

1. The code of the strategy's containing class doesn't have
   to be changed when a new strategy is added.
2. Once you've isolated the routine, things like Decorator
   become much easier.
3. Polymorphic dispatch coding is very simple. Case
   statements can become very complex.
4. Each strategy can have local variables and remember
   calls across time. A switch/case element requires
   tricks like:
        case XXX:
             { // Open a scope to allow local vars
               int x;
               static double last_answer; // Hidden memory
             }
             break;
5. I've accidentally left 'break' off of switch/case
   statements, but have never made any similar mistake with
   strategies.
6. You don't pay for the strategies you don't use. Every
   switch/case target is hard-coded into the switch/case. You
   have to link in all the support, even if you only use one
   option.
7. Flags are evil. ;-)
8. If you have a multifaceted abstraction, strategies allow
   you to mix-and-match cleanly. Using switch/case means you
   have to edit and bloat the code. Using inheritance means
   a cartesian explosion of classes -- Strategy is just good
   Dependency Management.

--
--------- There is no craftite * -------------
Tim Ottinger         Object Mentor      OO Training and

-------------------------------------------------------
We can interpret a bad temper as a sign of inferiority.
                                        -- Alfred Adler

 
 
 

Why is the Strategy Pattern better than a case statement

Post by jmedfor » Tue, 16 Feb 1999 04:00:00




> >One of the benefits that the GOF list for the Strategy Pattern is that
> >you can use it to replace case statements or conditionals.  Why is this
> >better?  I can see the advantage when each algorithm needs to create and
> >save information peculiar to that algorithm, and especially where the
> >choice of algorithm is made rarely. Am I thinking too much in terms of

> >efficiency and not enough in terms of clarity of design?

> You might have a single object representing a "stragegy" used in several
> place in your software maybe by calling different member functions.
> If you add another stragegy you don't need to change any existing code
> but if you used switch statements you'd need to go through your code finding
> and changing all of them.

> This is a good thing, it reduces the amount of coupling between the code
> making use of the algorithms and the algorithms themselves.

I was thinking that the conditional would be in a single subroutine that
could be called from multiple locations. Thus, adding another algorithm
would involve only adding another case statement to the one subroutine.
 
 
 

Why is the Strategy Pattern better than a case statement

Post by jmedfor » Tue, 16 Feb 1999 04:00:00




> > Why is the Strategy Pattern better than a case statement:

> 8. If you have a multifaceted abstraction, strategies allow
>    you to mix-and-match cleanly. Using switch/case means you
>    have to edit and bloat the code. Using inheritance means
>    a cartesian explosion of classes -- Strategy is just good
>    Dependency Management.

Could you explain this reason in more detail?
 
 
 

Why is the Strategy Pattern better than a case statement

Post by Robert C. Marti » Tue, 16 Feb 1999 04:00:00



>One of the benefits that the GOF list for the Strategy Pattern is that
>you can use it to replace case statements or conditionals.  Why is this
>better?  I can see the advantage when each algorithm needs to create and
>save information peculiar to that algorithm, and especially where the
>choice of algorithm is made rarely. Am I thinking too much in terms of
>efficiency and not enough in terms of clarity of design?

Neither.  The Strategy pattern is just as efficient as a switch/case
statement, and is probably less clear.  However it has one very powerful
advantage.

When you add a new case, you must find all the switch/case statements,
modify them, recompile them, redistribute them (if they are in shared
libraries or DLLs) etc.  But if you use the strategy pattern, you add a new
case by creating a new derivative of the strategy class.  *Nothing* else
changes.  No existing code changes.  New code is added.

This is an example of the "Open Closed Principle" which was described by
Bertrand Meyer in his classic "Object Oriented Software Construction",
Meyer, Prentice Hall, 1988.  If you'd like to read about this principle, and
other principles of OOD, then see the papers in the 'publications' section
of http://www.oma.com

Robert C. Martin    | Design Consulting   | Training courses offered:

14619 N Somerset Cr | Tel: (800) 338-6716 |   C++
Green Oaks IL 60048 | Fax: (847) 918-1023 | http://www.oma.com

TINCC.

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Brad Applet » Wed, 17 Feb 1999 04:00:00




>One of the benefits that the GOF list for the Strategy Pattern is that
>you can use it to replace case statements or conditionals.  Why is this
>better?

Because it allows you to separate *policy* from *mechanism* so that
they may be decoupled from one another into separate code modules.
Then when you want to add a new mechanism to implement the same policy
you don't have to touch any of the "policy" code. You only nned to
create a new and completely separate instance of a mechanism that
implements the policy. So you don't have to keep modifying the same
case-statement to add more cases.

Furthermore, I can reuse the "policy" code indepedently of the
currently implemented "mechanisms" that conform to the policy because
the code for each is separate, instead of both being part of the same
function in the same switch/case statement. I could reuse the policy
code in some other application, and only reuse maybe one or two of the
mechanisms (concrete strategies) and add some more of my own mechanism
in some entirely separate application that didn't need all the same
mechanisms as the one I reused the policy code from.

As for efficiency, sometimes polymorphism is more efficient than the
equivalent "case/switch" block because instead of comparing against
potentially multiple cases, you only do a single lookup to select the
appropriate method for the given object (and sometimes that "lookup"
can be determined at compile-time rather than runtime).

But the primary benefit here really has little to do with performance
or efficiency so much as it has to do with creating designs that are
more maintainable, adaptable, and hence reusable.

Cheers!
--

 "And miles to go before I sleep."   |  3700+ WWW links on CS & Sw-Eng

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Tim Ottinge » Wed, 17 Feb 1999 04:00:00





> > > Why is the Strategy Pattern better than a case statement:

> > 8. If you have a multifaceted abstraction, strategies allow
> >    you to mix-and-match cleanly. Using switch/case means you
> >    have to edit and bloat the code. Using inheritance means
> >    a cartesian explosion of classes -- Strategy is just good
> >    Dependency Management.

> Could you explain this reason in more detail?

Switch/case:
   switch(pay_type) {
          case Hourly:
              // calc pay
              switch(pay_delivery_type) {
                  case DirectDeposit:
                       // whatever
                       break;
                  case CheckMailedToEmployee:
                       // whatever
                       break;
             }
          case Salaried:
              switch(pay_delivery_type) {
                  case DirectDeposit:
                       // whatever
                       break;
                  case CheckMailedToEmployee:
                       // whatever
                       break;
             }

This is particularly ugly and will be hard to maintain. Every new
pay delivery type and every new pay calc type required this very
ugly code to be maintained, and (as written) you have to add every
pay delivery method in many places (once per pay calc type).

Admittedly this could be done better with one switch/case
on pay calc types, followed by one on pay delivery type, but
leaving off the break and interleaving the conditions are the
two most common errors I see in switch case -- after all, the
statement grows large, and people become impatient with reading.

Also, there is some chance that how you prepare the check may
be dependent on the details of how you calculate the pay, though
we try to eliminate any such dependency. In a switch/case statement,
it's no uglier than the code looks ALREADY, so you end up with a
switch on pay calc types, followed by a switch on pay delivery
type codes, where some of the pty delivery types will include
another switch on pay calc types... you can see the code becoming
increasing fragile.

Inheritance:
        +----------+
        | Employee |
        +----------+
        |/CalcPay/ |
        |/Pay/     |
        +----------+
            /_\
             |------------------+---------------------+
             |                  |                     |
        +----------+     +-------------+       +------------+
        |  Hourly  |     | PayByDeposit|       |  Salaried  |
        | employee |     |  Employee   |       |   Employee |
        +----------+     +-------------+       +------------+
        | CalcPay  |     | Pay         |       | CalcPay    |
        +----------+     +-------------+       +------------+
           /_\                 /_\              
            |                   |
            +-------------------+
                     |
              +---------------+
              | DirectDeposit |
              |   Hourly      |
              |   Employee    |
              +---------------+

YIKES! A cartesian explosion of leaf classes, all of which have the
deadly *inheritance diamond*!!!! It also approximates a routinely
poorly written switch/case statement, where the code is all compounded
and mixed all over, only in this case it's the inheritance that does
all the mixing. It's very messy, very fragile, and hard to extend.

The derived class has to deal with the differences in pay generation
based on different types perhaps, and it would be scribbled right
into the derived class methods. At least they're kept out of the
higher-level (non-leaf) classes.

Strategy:

       +-----------+      +----------+      +-------------+
       |/Pay Calc  |<-----| Employee |------|/PayDelivery |
       | Strategy/ |      |          |      |   Strategy/ |
       +-----------+      +----------+      +-------------+
           /_\                                  /_\
            |                                    |
       +------------+                       +------------+
       | Hourly Pay |                       |   Direct   |
       | Strategy   |                       |  Deposit   |
       +------------+                       +------------+

Here things are much more simple. Admittedly, it approximates
a very well written switch/case statement (with the 7 OTHER
good qualities). It is simple, it is clear, and it allows
these variable aspects (algorithms) to be treated uniformly
and extended seamlessly.

A dependency on the pay calc method can be handled by the
bidirectional linkage to employee, and methods can be created
in the pay calc strategy for it.

Good use of polymorphism, good use of Strategy, clean separation
of concerns.

--
--------- There is no craftite * -------------
Tim Ottinger         Object Mentor      OO Training and

-------------------------------------------------------
We can interpret a bad temper as a sign of inferiority.
                                        -- Alfred Adler

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Pete » Wed, 17 Feb 1999 04:00:00



> Switch/case:
>    switch(pay_type) {
>           case Hourly:
>               // calc pay
>               switch(pay_delivery_type) {
>                   case DirectDeposit:
>                        // whatever
>                        break;
>                   case CheckMailedToEmployee:
>                        // whatever
>                        break;
>              }
>           case Salaried:
>               switch(pay_delivery_type) {
>                   case DirectDeposit:
>                        // whatever
>                        break;
>                   case CheckMailedToEmployee:
>                        // whatever
>                        break;
>              }

Though the Dylan programming language has the equivalent of a select
statement, it is perhaps more natural to use Dylan's multi-method dispatch
capabilities.  The following Dylan code would accomplish the same thing as
the C/C++/Java code above.

define method pay (employee, pay-type == #"hourly", pay-delivery-type ==
#"direct-deposit")
  // whatever
end;

define method pay (employee, pay-type == #"hourly", pay-delivery-type ==
#"check-mailed-employee")
  // whatever
end;

define method pay (employee, pay-type == #"salaried", pay-delivery-type ==
#"check-mailed-employee")
  // whatever
end;

define method pay (employee, pay-type == #"salaried", pay-delivery-type ==
#"check-mailed-employee")
  // whatever
end;

--

Dylan... the high-performance dynamic language
 * open-source Unix version:  http://www.gwydiondylan.org/
 * free Win32 version: http://www.harlequin.com/products/ads/dylan/

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Tim Ottinge » Wed, 17 Feb 1999 04:00:00



> Though the Dylan programming language has the equivalent of a select
> statement, it is perhaps more natural to use Dylan's multi-method dispatch
> capabilities.  The following Dylan code would accomplish the same thing as
> the C/C++/Java code above.

I think this might be far preferable. When is the function call
resolved?
If it has at least as good a DM structure as the strategy method, then
we're in business, eh? :-)

--
--------- There is no craftite * -------------
Tim Ottinger         Object Mentor      OO Training and

-------------------------------------------------------
We can interpret a bad temper as a sign of inferiority.
                                        -- Alfred Adler

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Rick Jon » Thu, 18 Feb 1999 04:00:00



> One of the benefits that the GOF list for the Strategy Pattern is that
> you can use it to replace case statements or conditionals.  Why is
> this better?  I can see the advantage when each algorithm needs to
> create and save information peculiar to that algorithm, and especially

  > where the choice of algorithm is made rarely. Am I thinking too much
  > in terms of efficiency and not enough in terms of clarity of design?

It's worth bearing in mind that the Strategy principle was well
established long before OO (just nobody called it that).  Good C
programmers know it well, and the device-driver switch table in the Unix
kernel is a good example.

The basis in C is a structure of function pointers, and an instance of
the structure is filled with pointers to a set of functions that
implement a version of the strategy.  Code that uses the strategy simply
needs a pointer to a structure instance.  If you are interested in the
mechanics, a C++ vtable is almost exactly this.

A Unix device driver must implement such a set of functions and provide
a structure containing the pointers.  The kernel contains an array of
these structures, and when a device is referenced, picks one according
to the device number (which is in the device-file's inode entry).  Hence
the range of devices is arbitrarily extensible without kernel code
changes, with all devices having a uniform interface.  That's ultimately
the key benefit of the pattern.

The only real difference with an OO version is the ability of a strategy
instance to hold arbitrary private state.  Plus of course more elegant
coding.

--

 - Using OUI 1.9 Beta 6 from http://www.peaktopeak.com

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Pete » Thu, 18 Feb 1999 04:00:00




> as for efficiency: A virtual function call is (AFAIK) faster than an if
> and definitely faster than a switch.

What language could you possibly be talking about?

--

Dylan... the high-performance dynamic language
 * open-source Unix version:  http://www.gwydiondylan.org/
 * free Win32 version: http://www.harlequin.com/products/ads/dylan/

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Robb Shecte » Fri, 19 Feb 1999 04:00:00





> > as for efficiency: A virtual function call is (AFAIK) faster than an if
> > and definitely faster than a switch.

> What language could you possibly be talking about?

Umm,  this would be any language, wouldn't it?  OK, except maybe if your case
statement was based on an int value that could fit in a register on a
particular kind of hardware, and it could be compiled into a JMP.

- Robb

 
 
 

Why is the Strategy Pattern better than a case statement

Post by Tim Ottinge » Fri, 19 Feb 1999 04:00:00






> > > as for efficiency: A virtual function call is (AFAIK) faster than an if
> > > and definitely faster than a switch.

> > What language could you possibly be talking about?

> Umm,  this would be any language, wouldn't it?  OK, except maybe if your case
> statement was based on an int value that could fit in a register on a
> particular kind of hardware, and it could be compiled into a JMP.

Ummm... probably not. In C++, the polymorphic dispatch is done in
constant time. It's always exactly one indirection, and the compilers
optimize for  it. In some languages, polymorphic dispatch is via table
lookup. Some use has tables which essentially give approximate
constant
time, but where there is more delay (potentially) due to hashing
algorithms and lookup. Also, many of these do/did keep pointers to
superclasses, so that a message lookup may do a hash, get a 'miss' the
immediate class, be passed to a base class,  get a 'miss' in that
lookup, and go to the second-most-base class, where  another lookup
is done.

In such a situation (assuming worst case: linear search and a number
of
base classes) you could have performance *Much* worse than an 'if'.

But I think every language designer, compiler writer, and interpreter
writer has paid attention to the details and applied whatever
optimizations
they could think of. But I don't know that you can beat an 'if' in
languages other than C++. For instance, the message could have an
ID, and the message ID could *be* the hash. Also, things could be
optimized at compile or precompile time for bytecode interpreters.

You sure can beat the C++ if or switch with a polymorphic call,
though.

--
--------- There is no craftite * -------------
Tim Ottinger         Object Mentor      OO Training and

-------------------------------------------------------
We can interpret a bad temper as a sign of inferiority.
                                        -- Alfred Adler

 
 
 

1. this switch statement is executing mulitple cases ... why ?????

what is wrong with this switch statement?  if i enter '1' at the prompt, it
will instantiate only the Breed class.  if I choose '2', it will instantiate
BOTH the Breed AND the Canine classes.   i wish it would only instantiate
the one i want.

what fundamental C++ principal do I not understand here?

    cout << "Enter a choice below:\n\n";
    cout << "1.  Add A Breed\n";
    cout << "2.  Add A Canine\n";
    cout << "q.  Back To Main Menu\n";
    cout << "\nEnter Choice: ";
    char c = '\0';
    cin >> c;
    cin.ignore();
    switch (c)
    {
      case '1' :
        Breed();
        break;
      case '2' :
        Canine();
        break;
      default:
        exit(0);
    }

2. Electronic Books and Reader ?

3. Stupid Format Statement -- is there a better way?

4. OXM:Please need QUICK response!

5. Strategy pattern and optimization of a empty member

6. Help a newbie if you will

7. Error handling: strategies, patterns, solutions

8. comp.home.misc Welcome and FAQ

9. How does a Bridge differ from a Strategy Pattern?

10. strategy pattern

11. "Strategy" vs. "State" pattern -- no difference?

12. FS: Coad's Object Models: Strategies Patterns & Applications 2/e

13. Difference between Strategy & Bridge pattern?