CSE351 Design Patterns PDF
Document Details
Uploaded by HandyCerium8352
Akdeniz University
Tags
Summary
This document discusses the Strategy Pattern in object-oriented programming, using a duck simulation example called SimUDuck. It explores the benefits of using design patterns and interfaces for code flexibility and maintainability. The document also includes questions to test understanding.
Full Transcript
CSE351 DESIGN PATTERNS 01. STRATEGY PATTERN Someone has already solved your problems. It started with a simple SimUDuck app ▪ You are the designer of a highly successful duck pond simulation game, SimUDuck. ▪ Initial designers of the simulator used standard OO techniques and created one...
CSE351 DESIGN PATTERNS 01. STRATEGY PATTERN Someone has already solved your problems. It started with a simple SimUDuck app ▪ You are the designer of a highly successful duck pond simulation game, SimUDuck. ▪ Initial designers of the simulator used standard OO techniques and created one Duck superclass from which all other duck types inherit. Company executives think it’s time for a big innovation to show at the upcoming fair. 2 But now we need the ducks to FLY The executives decided that flying ducks is just what the simulator needs to blow away other duck sim competitors. And your manager told it’ll be no problem. ▪ After all you are an OO programmer, how hard it can be? 3 But something went horribly wrong… What happened? - Failed to notice that not all subclasses of Duck fly - Behavior is added to Duck superclass which is not appropriate for some Duck subclasses - A localized update to the code caused a non-local side effect (flying rubber ducks)! 4 Let’s think about inheritance… Sharpen your pencil Which of the following are disadvantages of using inheritance to provide Duck behavior? (choose all that apply) A. Code is duplicated across subclasses. B. Runtime behavior changes are difficult C. We can’t make ducks dance. D. Hard to gain knowledge of all duck behaviors. E. Ducks can’t fly and quack at the same time. F. Changes can unintentionally affect other ducks. 5 How about an interface? ▪ Inheritance probably wasn’t the answer ▪ Because execs now want to update the product every six months (in ways that haven’t decided yet). ▪ Will need to override fly() and quack() for every new Duck subclass ▪ Need a cleaner way to have only some (but not all) of the duck types fly or quack What do YOU think of this design? 6 What would you do instead? ▪ Not all subclasses should have flying or quacking behavior, so inheritance isn’t the right answer ▪ Having subclasses implement Flyable and/or Quackable partly solves the problem, but it destroys code reuse ▪ A different maintenance nightmare! ▪ Also there might be more than one kind of flying behavior among ducks that do fly ▪ Let’s figure out a solution the old-fashioned- way ▪ by applying good OO software design principles 7 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 programming in, what’s one true constant that will be always with you? ▪ No matter how well you design an application, over time an application must grow and change or it will die. 8 Zeroing in on the problem… Using inheritance hasn’t worked out well Duck behavior keeps changing across subclasses Flyable and Quackable interface sounded promising at first Except Java interfaces have no implementation code, no code reuse! Whenever you need a modification, you need to track down in all different subclasses As simple as it 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 9 Separating what changes from what stays the same ▪ fly() and quack() are the parts of the Duck class that vary across ducks. ▪ To separate these behaviors, let’s pull both methods out of the Duck class and create new set of classes to represent each behavior 10 Designing the Duck behaviors We’d like to keep things flexible. Assign behaviors to instances of Duck e.g., instantiate a new MallardDuck instance and initialize with a specific type of flying behavior YOUR TURN Now, explain how we did achieve programming to an interface rather an implementation in this example? Use an interface to represent each behavior, FlyBehavior and QuackBehavior Each implementation of a behavior will implement one of those interfaces Make sets of classes whose entire reason for living is to represent a behavior (e.g., squeaking), and it is the Behavior class rather than the Duck class, that will implement the behavior interface 11 really means ▪ The word interface is overloaded here. ▪ There’s the concept of interface, but there’s also java construct interface ▪ You can program to an interface, without using Java interface ▪ using an abstract class or interface – supertype (exploit polymorphism) Programming to an implementation would be: But programming to an interface/supertype would be: Even better, rather than hard-coding the instantiation of the subtype (like new Dog()), assign concrete implementation object at runtime: 12 Implementing the Duck Behaviors With this design, other types of objects can reuse our fly and quack behaviors because they are no longer hidden away in our Duck class! And we can add new behaviors without modifying any of our existing behavior classes or touching any of Duck classes that use flying behaviors 13 there are no Dumb Questions Q: Do I always have to implement my Q: It feels weird to have a class that’s just a application first, see where things are changing, behavior. Aren’t classes supposed to represent and then go back and separate & encapsulate them? things? Aren’t classes supposed to have both state AND behavior? A: Not always; often when you are designing an application you anticipate that might vary. A: In an OO system, yes, classes represent things Principles and patterns can be applied at any that generally have both state (instance variables) stage of development cycle. and Methods. Here, the thing happens to be a behavior. But even a behavior can still have state Q: Should we make Duck an interface too? and methods; a flying behavior might have instance variables representing attributes (beats per A: Not in this case. We’ve got everything hooked together, we do benefit by having Duck be a minute, max altitude and speed, etc.) for flying concrete class and having specific ducks, like behavior. MallardDuck, inherit common properties and methods. 14 Sharpen your pencil 1. Using our new design, what would you do if you needed to add rocket-powered flying to the SimUDuck app? Create a FlyRocketPowered class that implements the FlyBehavior interface. 2. Can you think of a class that might want to use the Quack behavior that isn’t a duck? One example, a duck call (a device that makes duck sounds). Another example is a charlatan or a mountebank person [check out here]. 15 Integrating the Duck Behavior The key is that a Duck will now delegate its flying and quacking behavior, instead of using quacking and flying methods defined in the Duck class (or subclass). 1. Add two instance variables to the 2. Also replace fly() and quack() in the Duck class Duck class called flyBehavior with performFly() and performQuack(). and quackBehavior declared as interface type. Each duck object will set these variables polymorphically to reference specific type it would like at runtime (FlyWithWings, Squeak, etc.). 3. Now implement performQuack() 16 More integration… 4. How the flyBehavior and quackBehavior instance variables are set. public class MallardDuck extends Duck { public MallardDuck() { quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); } public void display() { System.out.println(“I’m a real Mallard duck”); } } ▪ So 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 with the flying behavior. 17 ▪ Good catch, yes we do, just for now. ▪ We’ll fix it later with other Design Patterns. ▪ Still, we are setting the behaviors to concrete classes that we could easily change at runtime (through magic of polymorphism) Take a moment and think about how you ? would implement a duck so that its behavior could change at runtime. 18 Testing the Duck code Duck.java - also consider MallardDuck.java public abstract class Duck { FlyBehavior.java FlyWithWings.java FlyNoWay.java FlyBehavior flyBehavior; QuackBehavior quackBehavior; public interface FlyBehavior { public Duck() { public void fly(); } } public abstract void display(); public class FlyWithWings implements FlyBehavior { public void performFly() { public void fly() { flyBehavior.fly(); System.out.println(“I’m flying!!”); } } } public void performQuack() { quackBehavior.quack(); public class FlyNoWay implements FlyBehavior { } public void fly() { public void swim() { System.out.println(“I can’t fly”); System.out.println(“All ducks float, even decoys!”); } } } } 19 Testing the Duck code continued… Quack Behavior interface QuackBehavior.java, Quack.java, MuteQuack.java, and Squeak.java public interface QuackBehavior { public void quack(); MiniDuckSimulator.java } public class MiniDuckSimulator { public static void main(String[] args) { public class Quack implements QuackBehavior { Duck mallard = new MallardDuck(); public void quack() { mallard.performQuack(); System.out.println(“Quack”); mallard.performFly(); } } } } public class MuteQuack implements QuackBehavior { public void quack() { System.out.println(“>”); } Run the code } public class Squeak implements QuackBehavior { public void quack() { System.out.println(“Squeak”); } } 20 Setting behavior dynamically 1. Add two new methods to the Duck Class public void setFlyBehavior(FlyBehavior fb) { flyBehavior = fb; } public void setQuackBehavior(QuackBehavior qb) { quackBehavior = qb; } We can call these methods anytime we want to change the behavior of a duck on the fly 2. Make a new Duck type (ModelDuck.java) public class ModelDuck extends Duck { public ModelDuck() { 3. Make a new FlyBehavior type flyBehavior = new FlyNoWay(); (FlyRocketPowered.java) quackBehavior = new Quack(); } public class FlyRocketPowered implements FlyBehavior { public void display() { public void fly() { System.out.println(“I’m a model duck”); System.out.println(“I’m flying with a rocket!”); } } } } 21 4. Change the test class, add ModelDuck and make ModelDuck rocket-enabled, and run it! 22 The Big Picture on encapsulated behaviors Pay careful attention to the relationships. Now assign right relations to the appropriate arrows (IS-A, HAS-A and IMPLEMENTS) 23 HAS-A can be better than IS-A ▪ The HAS-A relationship is interesting: each duck has a FlyBehavior and a QuackBehavior to which it delegates flying and quacking. ▪ When you put two classes together you’re using composition. ▪ Instead of inheriting their behavior, the ducks get their behavior by composed with the right behavior object ▪ Creating systems using composition gives a lot flexibility. ▪ Not only encapsulating a family of algorithms into their own set of classes, but also letting change behavior at runtime ▪ Composition is used in many design patterns and you’ll see a lot more about its advantages and disadvantages 24 Speaking of Design Patterns ▪ You just applied a pattern – STRATEGY pattern. ▪ You used Strategy Pattern to rework the SimUDuck app. Thanks to this pattern, the simulator is ready for any changes those execs might cook up on their next business trip. ▪ Here is the formal definition. 25 Overheards Design patterns give you a shared vocabulary which elevates your thinking about architecture by letting you think at the pattern level, not the nitty gritty object level. What is the difference between these two orders? Not a thing! What’s Flo got that Alice doesn’t is a shared vocabulary. Easier to communicate with the cook and gives cook less to remember, because he’s got all dinner patterns. 26 The power of a shared vocabulary When you communicate using patterns you are doing more than just sharing LINGO. ✓ Shared pattern vocabularies are POWERFUL ✓Not just pattern name but a whole set of qualities, characteristics and constraints ✓Patterns allow you to say more with less ✓Talking at the pattern level allows you to stay «in the design» longer ✓Discuss at the design level not implementation ✓Shared vocabularies can turbo charge your team ✓Move more quickly with less misunderstanding ✓Shared vocabularies encourage junior developers to get up to speed ✓Seniors shall motivate juniors 27 How do I use Design Patterns? ▪ Think of off-the-shelf libraries and frameworks. THEY DON'T HELP ▪ Java APIs and all the functionality they give STRUCTURING YOUR CODE you: network, GUI, IO, etc. Design patterns don’t go directly into your code, they first go into your BRAIN. 28 there are no Dumb Questions Q: If design patterns are so great, why can’t Q: Aren’t libraries and frameworks also design someone build a library of them so I don’t have to? patterns? A: Design patterns are higher level than libraries. A: Frameworks and libraries are not design patterns; Design patterns tell us how to structure classes they provide specific implementations that we link and objects to solve certain problems and it is our into our code. Sometimes, however, libraries and job to adapt those designs to fit our particular frameworks make use of design patterns in their application. implementations. That’s great, because once you understand design patterns, you’ll more quickly understand APIs that are structured around design Q: So, there are no libraries of design patterns? patterns. A: No, but you will learn later about pattern catalogs with lists of patterns that you can apply to your applications. 29 Tools for your Design Toolbox Let’s look at the tools you’ve put in your OO toolbox. Bullet Points ▪ Knowing the OO basics does not make you a good OO designer ▪ Good OO designs are reusable, extensible and maintainable ▪ Patterns are proven OO experience ▪ Patterns don’t give you code, they give you general solutions to design problems. ▪ Patterns aren’t invented, they are discovered ▪ Most patterns and principles ▪ address issues of change in software ▪ allow some part of a system vary independently 30