views:

3379

answers:

8

Hi All,

I've been reading about the OCP principal and how to use the strategy pattern to accomplish this.

I was going to try and explain this to a couple of people, but the only example I can think of is using different validation classes based on what status an "order" is.

I've read a couple of articles online, but these don't usually describe a real like reason to use the strategy, like generating reports/bills/validation etc...

Are there any real world examples where you think a strategy pattern is common?

+9  A: 

What about this:

You have to encrypt a file.

For small files, you can use "in memory" strategy, where the complete file is read and kept in memory ( let's say for files < 1 gb )

For large files, you can use another strategy, where parts of the file are read in memory and partial encrypted results are stored in tmp files.

These may be two different strategies for the same task.

The client code would look the same:

 File file = getFile();
 Cipher c = CipherFactory.getCipher( file.size() );
 c.performAction();



// implementations:
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             // load in byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

The

     Cipher c = CipherFactory.getCipher( file.size() );

Would return the correct strategy instance for the cipher.

I hope this helps.

( I don't even know if Cipher is the right word :P )

OscarRyz
Is your example not more a Factory Pattern? Also I think it will not work in C# for example. Your "getCipher()" method is a static method but in C# you cannot define a static method on an interface (neither in Java I think but for this I'm not sure).
FrenchData
They go together. The Factory create the strategy, but the strategy it self hold the algorithm to perform the ( basically ) same operation. The strategy can also be changed at runtime. About the factory method you're correct, I have change it it.
OscarRyz
A: 

I have an application that synchronizes it's user base each day against our enterprise directory. User's are eligible or not eligible based on their status in the University. Each day the provisioning program goes through and makes sure that those who are supposed to be eligible are provisioned in the application and those who are not are de-provisioned (actually according to a graceful degradation algorithm, but that's beside the point). On Saturday I do a more thorough update that synchronizes some properties of each user as well as making sure that they have the proper eligibility. At the end of the month I do some bill back processing based on usage for that month.

I use a composable strategy pattern to do this synchronization. The main program basically chooses a master strategy depending on the day of the week (sync changes only/sync all) and the time of semester relative to the academic calendar. If the billing cycle is ending, then it also composes it with a billing strategy. It then runs the chosen strategy via a standard interface.

I don't know how common this is, but I felt like it was a perfect fit for the strategy pattern.

tvanfosson
A: 

I used the strategy approach in a fairly complex engine in an application that is a good example. Essentially the engine's role was to go and first find a list of people who had a widget, it's second role was to figure out which were the 10 best people with a widget based on an unknown number of parameters (things like price distance previous business together, ammount on stock, shipping options etc etc etc...)

Essentially what we did was we broke the problem into two strategies the first being data retrieval, as we knew that we had multiple sources of our widgets and we needed to be able to get the data and transform it to a common structure.

We then also realized that we had multiple algorithims some were based on weighting the parameters, others were very weird and propitery and I couldn't do them justice without pulling out visios and charts and well you get the picture, we had lots of algorithims for selecting the best people.

Our service itself was very thing it essentially defined the inputs, outputs and did some normalization of the data, it also used a provider pattern to plug-in the application specific data providers and algorithim providers which used the strategy. This was a fairly effective system.

We had some debates if we were using a strategy or a template pattern which we never resolved.

JoshBerke
A: 

A few weeks ago, I added a common Java interface which was implemented by one of our domain objects. This domain object was loaded from the database, and the database representation was a star schema with about 10+ branches. One of the consequences of having such a heavy weight domain object is that we've had to make other domain objects that represented the same schema, albeit less heavyweight. So I made the other lightweight objects implement the same interface. Put otherwise we had:

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

Originally, I wanted to use CollectibleElephant to sort Elephants. Pretty quickly, my teammates glommed onto CollectibleElephant to run security checks, filter them as they get sent to the GUI, etc.

Alan
+1  A: 

Are you sure that the status of an "order" is not a State pattern? I have a hunch that an order will not be handled differently depending on its status.

Take for example the method Ship on the Order:

order.Ship();
  • If the shipping method varies in function of its status, then you've got a strategy pattern.
  • If however the Ship() method succeeds only when the order has been paid, and the order has not been shipped yet, you've got a state pattern.

The best example of the state pattern (and other patterns) I found was in the book "Head First Design Patterns", which is amazing. A close second will be David Cumps' blogging series of patterns.

grootjans
A: 

We had to create a third-party provisioning interface for an enterprise platform with a very complicated database. The submission of data to be provisioned was as a list of our data types which were put into a priority queue in our application so they could be written to the database in the correct order due to dependencies.

The process to write that data was then quite simple, keep popping off the top of the priority queue and then choose a strategy based on the type of the object that you extract.

Coxy
A: 

I can think of several fairly simple examples:

  • Sorting a list. The strategy is the comparison used to decide which of two items in the list is "First"
  • You might have an application where the sorting algorithm itself (QuickSort, HeapSort, etc.) may be chosen at runtime
  • Appenders, Layouts, and Filters in Log4Net and Log4j
  • Layout Managers in UI toolkits
  • Data compression. You might have an ICompressor interface whose sole method looks something like this:

    byte[] compress(byte[] input);

    Your concrete compression classes might be things like RunLengthCompression, DeflateCompression, etc.

glaxaco
A: 

One common usage of the strategy pattern is to define custom sorting strategies (in languages without higher-order functions), e.g. to sort a list of strings by length in Java, passing an anonymous inner class (an implementation of the strategy interface):

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

In a similar manner, strategies can be used for native queries with object databases, e.g. in db4o:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});
Fabian Steeg