To Design Patterns or not to Design Patterns that is the question...

 

Of course those GoF patterns can make life hell for the maintenance developer or app framework user, when people turn it into a contest to see how many design patterns they can fit into a single project. The overall "Design Patterns" philosophy is really "how can I defer as many decisions as possible from compile time to run time?" This makes the code very flexible, but the flexibility is wasted when a consultant writes code using lots of patterns to puff up his ego and then leaves without leaving adequate comments or documentation. Without insight into how the system works, the configurability and flexibility that these patterns offer is lost. The system hardens into an opaque black box.
Deferring decisions to runtime makes code hard to read. Inheritance trees can get fairly deep, work is delegated off in clever but unintuitive ways to weird generic objects, and finding the code you're looking for is impossible, because when you're looking for the place where stuff actually happens, you eventually come across a polymorphic wonder like

object.work();

and the trail ends there. Simply reading the code doesn't tell you what it does; the subtype of object isn't determined until runtime. You basically need a debugger.

You can take a really simple program and screw it up with aggressive elegance like this. Here is Hello World in Java:

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, world!");
  }
}



But this isn't elegant enough. What if we want to print some other string? Or what if we want to do something else with the string, like draw "Hello World" on a canvas in Times Roman? We'd have to recompile. By fanatically applying patterns, we can defer to runtime all the decisions that we don't want to make at runtime, and impress later consultants with all the patterns we managed to cram into our code:


public interface MessageStrategy {
  public void sendMessage();
}

public abstract class AbstractStrategyFactory {
  public abstract MessageStrategy createStrategy(MessageBody mb);
}

public class MessageBody {
  Object payload;
  public Object getPayload() {
    return payload;
  }
  public void configure(Object obj) {
    payload = obj;
  }
  public void send(MessageStrategy ms) {
    ms.sendMessage();
  }
}

public class DefaultFactory extends AbstractStrategyFactory {
  private DefaultFactory() {;}
  static DefaultFactory instance;
  public static AbstractStrategyFactory getInstance() {
    if (instance==null) instance = new DefaultFactory();
    return instance;
  }

  public MessageStrategy createStrategy(final MessageBody mb) {
    return new MessageStrategy() {
      MessageBody body = mb;
      public void sendMessage() {
        Object obj = body.getPayload();
        System.out.println((String)obj);
      }
    };
  }
}

public class HelloWorld {
  public static void main(String[] args) {
    MessageBody mb = new MessageBody();
    mb.configure("Hello World!");
    AbstractStrategyFactory asf = DefaultFactory.getInstance();
    MessageStrategy strategy = asf.createStrategy(mb);
    mb.send(strategy);
  }
}



Look at the clean separation of data and logic. By overapplying patterns, I can build my reputation as a fiendishly clever coder, and force clients to hire me back since nobody else knows what all this elegant crap does. Of course, if the specifications were to change, the HelloWorld class itself would require recompilation. But not if we are even more clever and use XML to get our data and to encode the actual implementation of what is to be done with it. XML may not always be a good idea for every project, but everyone agrees that it's definitely cool and and should be used wherever possible to create elegant configuration nightmares.

 

Original source http://developers.slashdot.org/comments.pl?sid=33602&cid=3634763

This page was last updated on: 09/06/2009 05:05