Thanks, Peter,

This reply is in three parts: Oops, Ugh and GoF.

FIRST PART: Oops!

I am afraid there is a fatal flaw in your reasoning.  Your example of
the Strategy Pattern is *not* the Strategy Pattern.  It is merely two
differing implmentations of an interface.  The Strategy Pattern is a
client based pattern.  As the Gang of Four (GoF) in "Design Patterns:
Elements of Reusable Object-Oriented Software" said on the inside of
the cover:

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

So, your point about the Strategy Pattern, of course, does not work
and is a non-starter.


A Strategy Pattern most importantly introduces some Helper utility
interface for the various implementations of an algorithm.  Thus, you
could have either

A.  

interface IFormatDatabaseColumnWidth {
    public void setHelper(Helper helper);
    public void doWork();
}

or

B.

Inteface IFormatDatabaseColumnWidth {
    public void doWork();
}

But the implementations would have to be something like:

public class IFormatDatabaseColumnWidthImpl {
    private Helper helper;

    public void setHelper(Helper helper) {
        this.helper = helper;
    }

    public void doWork() {
        // Do business logic
        int value = helper.calcColumnWidth(data,metaData[]),columnNo);
        // Do more business logic
    }
}

Thus, there would be a Helper interface:

interface Helper {
     int calcColumnWidth(Object [][] data, MetaData metaData[]) int columnNo);
}

The differing calculations, then, would go into the Helper interface
implementations and not into the IFormatDatabaseColumnWidth interface
implementations.  So, you might have

public class AllRowsFDCW implements Helper {
    public int calcColumnWidth(Object [][] data, MetaData metaData[])
int columnNo) {
         // Slowest and most accurate algorithm iterates all rows in
the result set
    }
}

and 

public class First100FDCW implements Helper {
    public int calcColumnWidth(Object [][] data, MetaData metaData[])
int columnNo) {
         // Algorithm based on the first 100 rows
    }
}

and 

public class class StepwiseFDCW implements Helper {
    public int calcColumnWidth(Object [][] data, MetaData metaData[])
int columnNo) {
        // Algorithm that calculates the column width for every N rows
    }
}

Please note that the pattern essentially uses polymorphism and late
binding not through implementations of an interface but through a
composite pattern.

Thus, when inversion of control (IoC) is used with the Strategy
Pattern, whether you are doing Dependency Injection (DI) or Dependency
Lookup (DL), the Helper is what is the subject of the lookup or
injection.  (IoC, including DL, cannot be identified as DI merely.)

Your explanation of the Strategy Pattern leaves out what is essential
to the pattern.  Consequently, your explanation is merely how Chain of
Responsibiltiy (CoR) can be used instead of differing implementations
of an interface. See below for a short note on your CoR example.


On 6/1/05, Pilgrim, Peter <[EMAIL PROTECTED]> wrote:
> Consider a GUI algorithm that displays rows from the database.
> The typical problem is to work out the best column width for
> rendering the screen.
> 
> interface IFormatDatabaseColumnWidth {
>         public int calcColumnWidth( Object[][] data, MetaData metaData[], int
> columnNo );
> }
> 
> // Slowest and most accurate algorithm iterates all rows in the result set
> class AllRowsFDCW implements IFrameDatabaseColumnWidth {  ... }
> // Algorithm based on the first 100 rows
> class First100FDCW implements IFrameDatabaseColumnWidth {  ... }
> // Algorithm that calculates the column width for every N rows
> class StepwiseFDCW implements IFrameDatabaseColumnWidth {  ... }
> 
> This is the classic strategy pattern, as I remember writing it in a Swing/JDBC
> five years ago. (In fact Xenon-SQL is still out there somewhere, but it
> is broken against JDK 1.3 and 24/7/365 the time to fix it! )

SECOND PART: Ugh!

 In my opinion, by the way, as an aside, using the CoR to replace mere
implementations of an interface would be rather *nuts*.  This would
merely obfuscate and provide no benefit at all.  This is what our
fellow traveler Frank Zammettie finds inherently suspicious about the
*OOP nuts*.  This is, I am afraid, similar to some of the rather *knee
jerk* uses of CoR floating around.  How does that old saw go?  A boy
with a new hammer sees the whole world as a nail?

THIRD PART: GoF

The GoF used as their signal example a Composition class which
traversed and repaired (traverse(), repair()) and, much like your
algorithms with result sets, employed a field utility class Compositor
with the method compose() to implement various linebreaking strategies
(SimpleCompositor, TeXCompositor, and ArrayCompositor).

According to the GoF, who defined these things, the Strategy Pattern
must contain:

A Context interface holding a Strategy (which I called a "Helper")
interface that has varying ConcreteStrategy implementations holding
the optional algorithms (strategies).  Indeed, they suggested that you
might use inheritance to factor out the common factors in the
ConcreteStragey (Helper implementation) classes.

Let me be clear about something, as Richard Nixon said.  The Strategy
Pattern is used to eliminate conditional statements, among other
things.  So, if you are merely saying that CoR can also be used for
this, then that is clearly true.  Lots of patterns can be used for
that, including the questionable Template Method Pattern.  That does
not make the patterns equivalent.  I am not saying that you are saying
that does make them equivalent.  I am just saying that we need to make
sure we are not making that mistake.

Anyway, your example does not work because you understanding here of
the Strategy Pattern is flawed.  No?





> 
> You can rewrite the above strategy with Chain of Responsibility
> pedantically. If you have a very functional requirement for it.
> 
> class ChainFDCW implements IFrameDatabaseColumnWidth {
> 
>         Catalog catalog;
>         String  commandName;
> 
>         // IoC container friendly
>         public void setCatalog( catalog ) { ... }
>         public void setCommandName( name ) { ... }
> 
>         public int calcColumnWidth( Object[][] data, MetaData metaData[], int
> columnNo )
>         {
>                 Context context = new FDCWContext( data, metaData, columnNo );
>                 Command command = catalog.getCommand( commandName );
>                 command.execute( context );
>                 if ( context.isCalculatedOk() )
>                         return context.getColumnWidth();
>                 else
>                         throw new StrategyRuntimeException(
>                                 "Failed to calculate column width" );
>         }
> }
> 
> Ok writing a CoR for calculating data width takes a bit of stretching
> the imagination, but of course you can do it, which is the point.




-- 
"You can lead a horse to water but you cannot make it float on its back."
~Dakota Jack~

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to