if you’ve got some aspect of your code that is changing, say with every new requirement, then you know you’ve got a behavior that needs to be pulled out and separated from all the stuff that doesn’t change.
take the parts that vary and encapsulate them, so that later you can alter or extend the parts that vary without affecting those that don’t.
As simple as this concept is, it forms the basis for almost every design pattern. All patterns provide a way to let some part of a system vary independently of all other parts.
Separating what changes from what stays the same
Designing the Duck Behaviors
You can program to an interface without having to actually use a Java interface. The point is to exploit polymorphism by programming to a supertype so that the actual runtime object isn’t locked into the code. And we could rephrase “program to a supertype” as “the declared type of the variables should be a supertype, usually an abstract class or interface, so that the objects assigned to those variables can be of any concrete implementation of the supertype, which means the class declaring them doesn’t have to know about the actual object types!”
Implementing the Duck Behaviors
there are no Dumb Questions
Q: Do I always have to implement my application first, see where things are changing, and then go back to separate and encapsulate those things?
A: Not always; often when you are designing an application, you anticipate those areas that are going to vary and then go ahead and build the flexibility to deal with it into your code. You’ll find that the principles and patterns can be applied at any stage of the development lifecycle.
Integrating the Duck Behaviors
- First we’ll add two instance variables of type FlyBehavior and QuackBehavior
- Now we implement performQuack():
- Okay, time to worry about how the flyBehavior and quackBehavior instance variables are set. Let’s take a look at the MallardDuck class:
Setting behavior dynamically
- Add two new methods to the Duck class:
- Make a new Duck type (ModelDuck.java).
- Make a new FlyBehavior type (FlyRocketPowered.java).
- Change the test class (MiniDuckSimulator.java), add the ModelDuck, and make the ModelDuck rocket-enabled
The Big Picture on encapsulated behaviors
HAS-A can be better than IS-A
The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.