Chapter 1. Intro to Design Patterns: Welcome to Design Patterns

Images

Someone has already solved your problems. In this chapter, you’ll learn why (and how) you can exploit the wisdom and lessons learned by other developers who’ve been down the same design problem road and survived the trip. Before we’re done, we’ll look at the use and benefits of design patterns, look at some key object oriented design principles, and walk through an example of how one pattern works. The best way to use patterns is to load your brain with them and then recognize places in your designs and existing applications where you can apply them. Instead of code reuse, with patterns you get experience reuse.

It started with a simple SimUDuck app

Joe works for a company that makes a highly successful duck pond simulation game, SimUDuck. The game can show a large variety of duck species swimming and making quacking sounds. The initial designers of the system used standard OO techniques and created one Duck superclass from which all other duck types inherit.

Images
Images

In the last year, the company has been under increasing pressure from competitors. After a week long off-site brainstorming session over golf, the company executives think it’s time for a big innovation. They need something really impressive to show at the upcoming shareholders meeting in Maui next week.

But now we need the ducks to FLY

The executives decided that flying ducks is just what the simulator needs to blow away the competitors. And of course Joe’s manager told them it’ll be no problem for Joe to just whip something up in a week. “After all,” said Joe’s boss, “he’s an OO programmer... how hard can it be?”

Images
Images

But something went horribly wrong...

Images
Images

What happened?

Joe failed to notice that not all subclasses of Duck should fly. When Joe added new behavior to the Duck superclass, he was also adding behavior that was not appropriate for some Duck subclasses. He now has flying inanimate objects in the SimUDuck program.

A localized update to the code caused a non-local side effect (flying rubber ducks)!

Images
Images
Note

What Joe thought was a great use of inheritance for the purpose of reuse hasn’t turned out so well when it comes to maintenance.

Joe thinks about inheritance...

Images
Images

How about an interface?

Joe realized that inheritance probably wasn’t the answer, because he just got a memo that says that the executives now want to update the product every six months (in ways they haven’t yet decided on). Joe knows the spec will keep changing and he’ll be forced to look at and possibly override fly() and quack() for every new Duck subclass that’s ever added to the program... forever.

So, he needs a cleaner way to have only some (but not all) of the duck types fly or quack.

Images
Images

What do YOU think about this design?

What would you do if you were Joe?

Images

We know that not all of the subclasses should have flying or quacking behavior, so inheritance isn’t the right answer. But while having the subclasses implement Flyable and/or Quackable solves part of the problem (no inappropriately flying rubber ducks), it completely destroys code reuse for those behaviors, so it just creates a different maintenance nightmare. And of course there might be more than one kind of flying behavior even among the ducks that do fly...

At this point you might be waiting for a Design Pattern to come riding in on a white horse and save the day. But what fun would that be? No, we’re going to figure out a solution the old-fashioned way—by applying good OO software design principles.

Images

The one constant in software development

Okay, what’s the one thing you can always count on in software development?

No matter where you work, what you’re building, or what language you are programming in, what’s the one true constant that will be with you always?

Images

No matter how well you design an application, over time an application must grow and change or it will die.

Zeroing in on the problem...

So we know using inheritance hasn’t worked out very well, since the duck behavior keeps changing across the subclasses, and it’s not appropriate for all subclasses to have those behaviors. The Flyable and Quackable interface sounded promising at first—only ducks that really do fly will be Flyable, etc.—except Java interfaces typically have no implementation code, so no code reuse. In either case, whenever you need to modify a behavior, you’re often forced to track down and change it in all the different subclasses where that behavior is defined, probably introducing new bugs along the way!

Luckily, there’s a design principle for just this situation.

Images
Note

Take what varies and “encapsulate“ it so it won’t affect the rest of your code.

Note

The result? Fewer unintended consequences from code changes and more f lexibility in your systems!

In other words, 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.

Here’s another way to think about this principle: 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.

Okay, time to pull the duck behavior out of the Duck classes!

Separating what changes from what stays the same

Where do we start? As far as we can tell, other than the problems with fly() and quack(), the Duck class is working well and there are no other parts of it that appear to vary or change frequently. So, other than a few slight changes, we’re going to pretty much leave the Duck class alone.

Now, to separate the “parts that change from those that stay the same,” we are going to create two sets of classes (totally apart from Duck), one for fly and one for quack. Each set of classes will hold all the implementations of the respective behavior. For instance, we might have one class that implements quacking, another that implements squeaking, and another that implements silence.

Note

We know that fly() and quack() are the parts of the Duck class that vary across ducks.

Note

To separate these behaviors from the Duck class, we’ll pull both methods out of the Duck class and create a new set of classes to represent each behavior.

Images

Designing the Duck Behaviors

Note

So how are we going to design the set of classes that implement the fly and quack behaviors?

We’d like to keep things flexible; after all, it was the inflexibility in the duck behaviors that got us into trouble in the first place. And we know that we want to assign behaviors to the instances of Duck. For example, we might want to instantiate a new MallardDuck instance and initialize it with a specific type of flying behavior. And while we’re there, why not make sure that we can change the behavior of a duck dynamically? In other words, we should include behavior setter methods in the Duck classes so that we can change the MallardDuck’s flying behavior at runtime.

Given these goals, let’s look at our second design principle:

Images
Note

From now on, the Duck behaviors will live in a separate class—a class that implements a particular behavior interface.

Note

That way, the Duck classes won’t need to know any of the implementation details for their own behaviors.

We’ll use an interface to represent each behavior—for instance, FlyBehavior and QuackBehavior—and each implementation of a behavior will implement one of those interfaces.

So this time it won’t be the Duck classes that will implement the flying and quacking interfaces. Instead, we’ll make a set of classes whose entire reason for living is to represent a behavior (for example, “squeaking”), and it’s the behavior class, rather than the Duck class, that will implement the behavior interface.

This is in contrast to the way we were doing things before, where a behavior came either from a concrete implementation in the superclass Duck, or by providing a specialized implementation in the subclass itself. In both cases we were relying on an implementation. We were locked into using that specific implementation and there was no room for changing the behavior (other than writing more code).

With our new design, the Duck subclasses will use a behavior represented by an interface (FlyBehavior and QuackBehavior), so that the actual implementation of the behavior (in other words, the specific concrete behavior coded in the class that implements the FlyBehavior or QuackBehavior) won’t be locked into the Duck subclass.

Images

“Program to an interface” really means “Program to a supertype.”

Images

The word interface is overloaded here. There’s the concept of interface, but there’s also the Java construct interface. 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!”

This is probably old news to you, but just to make sure we’re all saying the same thing, here’s a simple example of using a polymorphic type—imagine an abstract class Animal, with two concrete implementations, Dog and Cat.

Programming to an implementation would be:

Images

But programming to an interface/supertype would be:

Images

Even better, rather than hardcoding the instantiation of the subtype (like new Dog()) into the code, assign the concrete implementation object at runtime:

Images
Images

Implementing the Duck Behaviors

Here we have the two interfaces, FlyBehavior and QuackBehavior, along with the corresponding classes that implement each concrete behavior:

Images
Images

Answers:

1) Create a FlyRocketPowered class that implements the FlyBehavior interface.

2) One example, a duck call (a device that makes duck sounds).

Integrating the Duck Behavior

Note

Here’s the key: a Duck will now delegate its flying and quacking behavior, instead of using quacking and flying methods defined in the Duck class (or subclass).

Here’s how:

  1. First we’ll add two instance variables of type FlyBehavior and QuackBehavior—let’s call them flyBehavior and quackBehavior. Each concrete duck object will assign to those variables a specific behavior at runtime, like FlyWithWings for flying and Squeak for quacking.

    We’ll also remove the fly() and quack() methods from the Duck class (and any subclasses) because we’ve moved this behavior out into the FlyBehavior and QuackBehavior classes.

    We’ll replace fly() and quack() in the Duck class with two similar methods, called performFly() and performQuack(); you’ll see how they work next.

    Images
  2. Now we implement performQuack():

    Images

    Pretty simple, huh? To perform the quack, a Duck just asks the object that is referenced by quackBehavior to quack for it. In this part of the code we don’t care what kind of object the concrete Duck is, all we care about is that it knows how to quack()!

More integration...

  1. Okay, time to worry about how the flyBehavior and quackBehavior instance variables are set. Let’s take a look at the MallardDuck class:

    Images

    MallardDuck’s quack is a real live duck quack, not a squeak and not a mute quack. When a MallardDuck is instantiated, its constructor initializes the MallardDuck’s inherited quackBehavior instance variable to a new instance of type Quack (a QuackBehavior concrete implementation class).

    And the same is true for the duck’s flying behavior—the MallardDuck’s constructor initializes the flyBehavior instance variable with an instance of type FlyWithWings (a FlyBehavior concrete implementation class).

    Images

    Good catch, that’s exactly what we’re doing... for now.

    Later in the book we’ll have more patterns in our toolbox that can help us fix it.

    Still, notice that while we are setting the behaviors to concrete classes (by instantiating a behavior class like Quack or FlyWithWings and assigning it to our behavior reference variable), we could easily change that at runtime.

    So, we still have a lot of flexibility here. That said, we’re doing a poor job of initializing the instance variables in a flexible way. But think about it: since the quackBehavior instance variable is an interface type, we could (through the magic of polymorphism) dynamically assign a different QuackBehavior implementation class at runtime.

    Take a moment and think about how you would implement a duck so that its behavior could change at runtime. (You’ll see the code that does this a few pages from now.)

Testing the Duck code

  1. Type and compile the Duck class below (Duck.java), and the MallardDuck class from two pages back (MallardDuck.java).

    Images
  2. Type and compile the FlyBehavior interface (FlyBehavior.java) and the two behavior implementation classes (FlyWithWings.java and FlyNoWay.java).

    Images
  3. Type and compile the QuackBehavior interface (QuackBehavior.java) and the three behavior implementation classes (Quack.java, MuteQuack.java, and Squeak.java).

    Images
  4. Type and compile the test class (MiniDuckSimulator.java).

    Images
  5. Run the code!

Images

Setting behavior dynamically

What a shame to have all this dynamic talent built into our ducks and not be using it! Imagine you want to set the duck’s behavior type through a setter method on the duck subclass, rather than by instantiating it in the duck’s constructor.

  1. Add two new methods to the Duck class:

    Images
  2. Make a new Duck type (ModelDuck.java).

    Images
  3. Make a new FlyBehavior type (FlyRocketPowered.java).

    Images
  4. Change the test class (MiniDuckSimulator.java), add the ModelDuck, and make the ModelDuck rocket-enabled.

    Images
  5. Run it!

Note

To change a duck’s behavior at runtime, just call the duck’s setter method for that behavior.

The Big Picture on encapsulated behaviors

Note

Okay, now that we’ve done the deep dive on the duck simulator design, it’s time to come back up for air and take a look at the big picture.

Below is the entire reworked class structure. We have everything you’d expect: ducks extending Duck, fly behaviors implementing FlyBehavior, and quack behaviors implementing QuackBehavior.

Notice also that we’ve started to describe things a little differently. Instead of thinking of the duck behaviors as a set of behaviors, we’ll start thinking of them as a family of algorithms. Think about it: in the SimUDuck design, the algorithms represent things a duck would do (different ways of quacking or flying), but we could just as easily use the same techniques for a set of classes that implement the ways to compute state sales tax by different states.

Pay careful attention to the relationships between the classes. In fact, grab your pen and write the appropriate relationship (IS-A, HAS-A, and IMPLEMENTS) on each arrow in the class diagram.

Images

HAS-A can be better than IS-A

The HAS-A relationship is an interesting one: each duck has a FlyBehavior and a QuackBehavior to which it delegates flying and quacking.

When you put two classes together like this you’re using composition. Instead of inheriting their behavior, the ducks get their behavior by being composed with the right behavior object.

This is an important technique; in fact, it is the basis of our third design principle:

Images

As you’ve seen, creating systems using composition gives you a lot more flexibility. Not only does it let you encapsulate a family of algorithms into their own set of classes, but it also lets you change behavior at runtime as long as the object you’re composing with implements the correct behavior interface.

Composition is used in many design patterns and you’ll see a lot more about its advantages and disadvantages throughout the book.

Speaking of Design Patterns...

Note

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.

Note

Use THIS definition when you need to impress friends and influence key executives.

Images

Design Puzzle

Below you’ll find a mess of classes and interfaces for an action adventure game. You’ll find classes for game characters along with classes for weapon behaviors the characters can use in the game. Each character can make use of one weapon at a time, but can change weapons at any time during the game. Your job is to sort it all out...

(Answers are at the end of the chapter.)

Your task:

  1. Arrange the classes.

  2. Identify one abstract class, one interface, and eight classes.

  3. Draw arrows between classes.

    a. Draw this kind of arrow for inheritance (“extends”). Images

    b. Draw this kind of arrow for interface (“implements”). Images

    c. Draw this kind of arrow for “HAS-A”. Images

  4. Put the method setWeapon() into the right class.

Images

Overheard at the local diner...

Images

What’s the difference between these two orders? Not a thing! They’re both the same order, except Alice is using twice the number of words and trying the patience of a grumpy short-order cook.

What’s Flo got that Alice doesn’t? A shared vocabulary with the short-order cook. Not only does that make it easier to communicate with the cook, but it gives the cook less to remember because he’s got all the diner patterns in his head.

Design Patterns give you a shared vocabulary with other developers. Once you’ve got the vocabulary you can more easily communicate with other developers and inspire those who don’t know patterns to start learning them. It also elevates your thinking about architectures by letting you think at the pattern level, not the nitty-gritty object level.

Overheard in the next cubicle...

Images
Images

The power of a shared pattern vocabulary

Note

When you communicate using patterns you are doing more than just sharing LINGO.

Shared pattern vocabularies are POWERFUL. When you communicate with another developer or your team using patterns, you are communicating not just a pattern name but a whole set of qualities, characteristics, and constraints that the pattern represents.

Note

“We’re using the Strategy Pattern to implement the various behaviors of our ducks.” This tells you the duck behavior has been encapsulated into its own set of classes that can be easily expanded and changed, even at runtime if needed.

Patterns allow you to say more with less. When you use a pattern in a description, other developers quickly know precisely the design you have in mind.

Talking at the pattern level allows you to stay “in the design” longer. Talking about software systems using patterns allows you to keep the discussion at the design level, without having to dive down to the nitty-gritty details of implementing objects and classes.

Note

How many design meetings have you been in that quickly degrade into implementation details?

Shared vocabularies can turbo-charge your development team. A team well versed in design patterns can move more quickly with less room for misunderstanding.

Note

As your team begins to share design ideas and experience in terms of patterns, you will build a community of patterns users.

Shared vocabularies encourage more junior developers to get up to speed. Junior developers look up to experienced developers. When senior developers make use of design patterns, junior developers also become motivated to learn them. Build a community of pattern users at your organization.

Note

Think about starting a patterns study group at your organization. Maybe you can even get paid while you’re learning...

How do I use Design Patterns?

We’ve all used off-the-shelf libraries and frameworks. We take them, write some code against their APIs, compile them into our programs, and benefit from a lot of code someone else has written. Think about the Java APIs and all the functionality they give you: network, GUI, IO, etc. Libraries and frameworks go a long way towards a development model where we can just pick and choose components and plug them right in. But... they don’t help us structure our own applications in ways that are easier to understand, more maintainable and flexible. That’s where Design Patterns come in.

Design patterns don’t go directly into your code, they first go into your BRAIN. Once you’ve loaded your brain with a good working knowledge of patterns, you can then start to apply them to your new designs, and rework your old code when you find it’s degrading into an inflexible mess.

Images
Images

Developer: Okay, hmm, but isn’t this all just good object-oriented design; I mean as long as I follow encapsulation and I know about abstraction, inheritance, and polymorphism, do I really need to think about Design Patterns? Isn’t it pretty straightforward? Isn’t this why I took all those OO courses? I think Design Patterns are useful for people who don’t know good OO design.

Guru: Ah, this is one of the true misunderstandings of object-oriented development: that by knowing the OO basics we are automatically going to be good at building flexible, reusable, and maintainable systems.

Developer: No?

Guru: No. As it turns out, constructing OO systems that have these properties is not always obvious and has been discovered only through hard work.

Developer: I think I’m starting to get it. These, sometimes non-obvious, ways of constructing object-oriented systems have been collected...

Guru: ...yes, into a set of patterns called Design Patterns.

Developer: So, by knowing patterns, I can skip the hard work and jump straight to designs that always work?

Guru: Yes, to an extent, but remember, design is an art. There will always be tradeoffs. But, if you follow well thought-out and time-tested design patterns, you’ll be way ahead.

Developer: What do I do if I can’t find a pattern?

Images

Guru: There are some object-oriented principles that underlie the patterns, and knowing these will help you to cope when you can’t find a pattern that matches your problem.

Developer: Principles? You mean beyond abstraction, encapsulation, and...

Guru: Yes, one of the secrets to creating maintainable OO systems is thinking about how they might change in the future, and these principles address those issues.

Images

Tools for your Design Toolbox

You’ve nearly made it through the first chapter! You’ve already put a few tools in your OO toolbox; let’s make a list of them before we move on to Chapter 2.

Images
Images

Design Patterns Crossword

Let’s give your right brain something to do.

It’s your standard crossword; all of the solution words are from this chapter.

Images

ACROSS

2. ________ what varies.

4. Design patterns __________.

6. Java IO, Networking, Sound.

9. Rubber ducks make a __________.

13. Bartender thought they were called.

15. Program to this, not an implementation.

17. Patterns go into your _________.

18. Learn from the other guy’s ___________.

19. Development constant.

20. Patterns give us a shared ____________.

DOWN

1. Patterns _______ in many applications.

3. Favor this over inheritance.

5. Dan was thrilled with this pattern.

7. Most patterns follow from OO _________.

8. Not your own __________.

10. High level libraries.

11. Joe’s favorite drink.

12. Pattern that fixed the simulator.

13. Duck that can’t quack.

14. Grilled cheese with bacon.

15. Duck demo was located here.

Images

Design Puzzle Solution

Character is the abstract class for all the other characters (King, Queen, Knight, and Troll), while WeaponBehavior is an interface that all weapon behaviors implement. So all actual characters and weapons are concrete classes.

To switch weapons, each character calls the setWeapon() method, which is defined in the Character superclass. During a fight the useWeapon() method is called on the current weapon set for a given character to inflict great bodily damage on another character.

Images
Images

Design Patterns Crossword Solution

Images
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset