5

I am taking a design patterns class in school, and have read through some chapters of Head First Design Patterns. What I'd like to find out is up to what extent can design patterns prevent rewriting of existing code.

Let us take Duck classes and FlyBehavior classes for example. I have in public static void main(String[] args) the following code:

Duck mallard = new MallardDuck(new FlyWithWings());

Am I right in saying that it is inevitable that you'll have to modify your main() method when you want to add a new strategy? In that way, you are modifying existing code, right? I am specifically referring to the part where a concrete strategy class is mentioned: new FlyWithWings().

If you implemented the factory method pattern in your code, you could prevent having a concrete class (FlyWithWings) from being mentioned at all:

public FlyBehavior returnBehavior(FlyBehaviorFactory factory, String behaviorType) {
    return factory.getFlyBehavior(behaviorType);
}

And thus, have the following line of code:

Duck mallard = new MallardDuck(returnBehavior(flyFactory, "wings"));

This way, a certain portion of your program does not have to know about what FlyBehaviorFactory to use. Yet, your main() method will still have to specify certain parameters in the returnBehavior method in order to know what factory will create what strategy. Thus, am I right in saying that you'll still have to modify main() if I added a new FlyBehavior class, and wanted to add that as a parameter to returnBehavior()?

Can one improve this situation any further?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Synchro
  • 51
  • 2
  • You should have a look at [_dependency injection_](http://en.wikipedia.org/wiki/Dependency_injection) and the various frameworks for it. – Seelenvirtuose Apr 26 '15 at 07:56

2 Answers2

0

In the current example, you are hard-coding the parameters passed to your factory and are thus deciding the behavior at compile time.

Duck mallard = new MallardDuck(returnBehavior(flyFactory, "wings"));

This can be changed to plugin a particular behavior at runtime instead of compile time :

Duck mallard = new MallardDuck(returnBehavior(flyFactory, args[0]));

With the above change, you will never have to change your main method. Your factory can be written in a way that it throws an exception when a behavior recieved at runtime is not available :

if(behaviorType.equals("wings") {
   //...create FlyWithWings
} else{
  //throw an appropriate exception indicating that the behavior does not exist
}

That being said, it is inevitable to change code if a new behavior is introduced. Although, this change will be in one single place and as far behind in your application as possible, i.e your factory which is the whole point of factory in the first place. Also, when you create a new FlyBehavior, you are doing so by extending from an existing class. This is inline with the open-closed principle

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
0

What you are doing here is dependency injection, you are injecting the FlyBehaviour into Duck. Sometimes when using dependency injection like this you can have a chain of injections. For example if you wanted a speed strategy to be injection into FlyBehaviour you might have something like this.

Duck mallard = new MallardDuck(new FlyWithWings(new FastSpeed()));

It wouldn't be nice to have main and any other class that uses Duck to have to know about all of these classes and have to change everytime any of these did. A better solution would be to use a dependency injection container which is responsible for creating each of these classes. Then in main you can just call something like this

Duck mallard = (Duck) Container.get('Duck');

The container is responsible for creating all the instances needed for the injection. So to answer your question you will need to change your code when wanting a new strategy but at least this way it is only in one place instead of throughout your code which could be many files.

user2802557
  • 747
  • 1
  • 9
  • 19