Strategy pattern Flashcards

Learn Strategy pattern here! (60 cards)

1
Q

Q: What key concepts are introduced on Page 1 of the Strategy Pattern chapter?

A

A:

Purpose of Design Patterns:

Reuse solutions from experienced developers who solved similar problems

“Load your brain” with patterns to recognize where to apply them

Focus on experience reuse rather than just code reuse

Core Idea:

Someone has already solved your design problems

Exploit collective wisdom through patterns

Chapter Preview:

Covers pattern benefits

Key OO design principles

Walkthrough of a pattern example

Tone Setting:

Playful analogy: “Objectville” and “Jim and Betty’s patterns group”

Emphasizes practical, community-vetted solutions

Bonus Mnemonic:
“REP your brain” → Recognize patterns, Experience reuse, Practical solutions.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Flashcard 1 (Initial Design)
Q: What was the original OO design of the SimUDuck app?

A

A:

Duck superclass with inherited methods:

quack() and swim() (concrete implementations)

display() (abstract, forced implementation by subclasses)

Subclasses:

MallardDuck, RedheadDuck, etc. (override display())

Key Limitation:
❌ All ducks inherit fly(), even inappropriate ones (e.g., RubberDuck).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Flashcard 2 (Problem Trigger)
Q: What change triggered the design problem?

A

A:

New requirement: Ducks must fly to compete with rivals.

Flawed solution: Added fly() to Duck superclass → Rubber ducks flew unintentionally.

Side Effect:
🔥 “Localized update caused non-local side effects” (flying rubber ducks).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Flashcard 3 (Inheritance Issues)
Q: Why was overriding fly() in subclasses a bad solution?

A

A:

Duplication: Override fly() to do nothing in RubberDuck, DecoyDuck, etc.

Maintenance hell: Future ducks require repetitive overrides.

No reuse: Each subclass manages behavior independently.

Example:

class RubberDuck {
fly() { /* do nothing */ } // Redundant!
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Flashcard 4 (Failed Interface Attempt)
Q: How did interfaces (Flyable, Quackable) fail to solve the problem?

A

A:
Pros: Only flying ducks implement Flyable.

Cons:
No code reuse: Each class reimplements behavior.

Runtime changes impossible: Behaviors hardcoded per class.
Diagram:

Duck → (no fly/quack)

MallardDuck → implements Flyable, Quackable
RubberDuck → implements Quackable

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Flashcard 5 (Key Insight)
Q: What was the critical realization about the design flaw?

A

A:

Root cause: Inheritance mixes what varies (fly/quack) with what stays the same (swim/display).

Solution needed: Separate behaviors that change (fly/quack) from stable ones.

Principle Preview:
🔧 “Encapsulate what varies.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Visual Summary

A

Visual Summary
Original Design:

Copy
Duck
/ | \
Mallard Rubber Decoy
Problem: All ducks forced to inherit fly/quack.

Interface Attempt:

Copy
Duck
/ | \
Mallard (Flyable) Rubber (Quackable)
Problem: Duplicated code, no flexibility.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Flashcard 1 (Inheritance Override Pitfall)
Q: Why was overriding fly()/quack() in subclasses like RubberDuck a poor solution?

A

A:
Duplication: Every non-flying duck (e.g., RubberDuck, DecoyDuck) must override fly() to do nothing.

Brittle: Adding new ducks forces repetitive overrides.

Violates DRY: Same “do nothing” code appears in multiple classes.

Code Example:
class RubberDuck {
fly() { /* Empty override / }
quack() { /
Squeak */ }
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Flashcard 2 (Inheritance Disadvantages)
Q: What are the 6 key disadvantages of using inheritance for duck behaviors? (Page 5 “Sharpen Your Pencil”)

A

A:
Code duplication across subclasses (A)

Runtime behavior changes are difficult (B)

Hard to track all duck behaviors (D)

Changes unintentionally affect other ducks (F)
(C and E are red herrings – dancing and simultaneous actions aren’t relevant)

Key Quote:

“What he thought was a great use of inheritance for reuse turned out poorly for maintenance.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Flashcard 3 (Interface Attempt)
Q: How did the Flyable/Quackable interface approach fail? (Page 6)

A

Pros: Only flying ducks implement Flyable.

Cons:

No code reuse: Each class rewrites fly()/quack().

Maintenance nightmare: Changing behavior requires updating all implementers.

No runtime flexibility: Behaviors locked at compile time.

Visual:

Duck → (no fly/quack)

MallardDuck → implements Flyable (writes fly() from scratch)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Flashcard 4 (Critical Insight)
Q: What fundamental problem did both failed approaches share? (Page 7)

A

A:

Both tightly coupled behaviors to the Duck class hierarchy:

Inheritance: Behaviors baked into superclass/subclasses.

Interfaces: Behaviors scattered across implementers.

Solution Needed: Decouple behaviors entirely.

Design Principle Teaser:
🔧 “Program to an interface, not an implementation.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Flashcard 5 (Why Interfaces Fell Short)
Q: Why didn’t interfaces solve the code reuse problem? (Page 6-7)

A

A:
Java interfaces lack implementation code:

Every Flyable duck rewrites fly().

No shared default behavior (e.g., FlyWithWings).

Example:
MallardDuck and RedheadDuck both write identical fly() code.

Key Quote:
“It completely destroys code reuse […] creating a different maintenance nightmare.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Flashcard 6 (Transition to Strategy)
Q: What hint does the text give about the upcoming solution? (Page 7 bottom)

A

A:

Clue: “We’re going to figure out a solution by applying good OO design principles.”

Principles Foreshadowed:

Encapsulate what varies.

Program to interfaces.

Favor composition.

Analogy:

“Wouldn’t it be dreamy if […] we could change [code] with the least possible impact?”

Summary Table: Failed Solutions

Approach Pros
Cons

Inheritance Reuse via inheritance
Inflexible, duplicates
code

Interfaces Selective behavior
No reuse,
maintenance hell

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Flashcard 1 (Core Principle - Page 9)
Q: What is the first design principle introduced, and how does it address the duck problem?

A

A:
Principle: “Identify the aspects that vary and separate them from what stays the same.”
Application:

Varies: Fly/quack behaviors

Stable: Swim/display methods
Key Insight: Encapsulate fly/quack into separate classes to isolate changes.

Quote:
“Take the parts that vary and encapsulate them so later you can alter them without affecting stable parts.”

Flashcard 2 (Encapsulation - Page 9)
Q: How does encapsulation enable flexibility in the duck design?
A:

Isolates change: Modifying fly behavior (e.g., adding FlyRocketPowered) doesn’t touch Duck classes.

Extensible: New behaviors can be added without rewriting existing code.
Visual:
Duck → Delegates to → FlyBehavior (encapsulated)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Flashcard 3 (Second Principle - Page 11)
Q: What does “Program to an interface, not an implementation” mean?

A

A:
Declare variables as interface types (e.g., FlyBehavior)

Avoid concrete dependencies: Ducks depend on FlyBehavior interface, not FlyWithWings class.
Code Contrast:

// BAD: Tied to concrete class
FlyWithWings f = new FlyWithWings();

// GOOD: Uses interface
FlyBehavior f = new FlyWithWings();

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Flashcard 4 (Interface vs. Implementation - Page 12)
Q: Why is the FlyBehavior interface superior to inheritance or Java interfaces?

A

A:
Polymorphism: Ducks work with any FlyBehavior implementation.

Reuse: FlyWithWings can be shared across ducks (unlike Java interfaces).
Key Quote:

“The declared type should be a supertype (interface/abstract class) so objects can be any concrete implementation.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Flashcard 5 (Design Impact - Page 11-12)
Q: How do these principles transform the duck design?

A

A:
Behaviors become families of algorithms:

FlyBehavior: FlyWithWings, FlyNoWay, etc.

Ducks delegate behaviors:

performQuack() → Calls quackBehavior.quack()

Runtime flexibility: Behaviors can be swapped dynamically.

Diagram:

Duck → HAS-A → FlyBehavior (interface)

FlyWithWings (implementation)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Flashcard 6 (Polymorphism Example - Page 12)
Q: How does the Animal example illustrate “programming to a supertype”?

A

A:
Bad: Dog d = new Dog(); ← Locks code to Dog

Good: Animal a = new Dog(); ← Works with any Animal subtype
Critical Idea:

“We don’t care about the concrete type—only that it can makeSound().”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Flashcard 7 (Terminology - Page 12)
Q: Clarify the overloaded term “interface” in design principles.

A

A:
Conceptual: “Program to a supertype” (interface/abstract class)

Java: interface keyword is one way to achieve it.
Key Distinction:

Goal: Exploit polymorphism by coding to abstractions.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Flashcard 8 (Behavior Classes - Page 11)
Q: Why are fly/quack behaviors now separate classes?

A

A:
Reuse: FlyWithWings can be used by MallardDuck, RedheadDuck, etc.

Single Responsibility: Each class handles one behavior variation.
Example:

Quack: Normal quacking

Squeak: Rubber ducks

MuteQuack: Decoys

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Flashcard 9 (Principle to Pattern - Page 12)
Q: How do these principles lead to the Strategy Pattern?

A

A:

Encapsulate variations → Separate fly/quack behaviors

Program to interfaces → FlyBehavior/QuackBehavior

Composition over inheritance → Ducks have behaviors, don’t inherit them.

Pattern Preview:

“Strategy defines a family of algorithms, encapsulates each, and makes them interchangeable.”

Summary Table: Principles
Principle Key Action Duck Example
Encapsulate what varies Separate fly/quack Extract to FlyBehavior

Program to interfaces Depend on FlyBehavior Not FlyWithWings

Favor composition (implied, Page 11) Ducks have behaviors HAS-A over IS-A

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Flashcard 1 (Behavior Interfaces - Page 13)
Q: What are the two core behavior interfaces and their methods?

A

A:

FlyBehavior → fly()

QuackBehavior → quack()
Key Point:
Each interface represents a family of algorithms (e.g., flying/quacking variations).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Flashcard 2 (FlyBehavior Implementations - Page 13)
Q: Name and describe the two FlyBehavior concrete classes.

A

A:

FlyWithWings: Implements flying for ducks with wings (I’m flying!!)

FlyNoWay: For non-flying ducks (I can’t fly).
Code:

public class FlyWithWings implements FlyBehavior {
public void fly() { System.out.println(“I’m flying!!”); }
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Flashcard 3 (QuackBehavior Implementations - Page 13)
Q: List the three QuackBehavior implementations and their purposes.

A

A:
Quack: Normal duck quack

Squeak: Rubber duck squeak

MuteQuack: Silent (for decoys).
Hierarchy:

QuackBehavior (interface)
├─ Quack
├─ Squeak
└─ MuteQuack

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Flashcard 4 (Duck Class Changes - Page 15) Q: How is the Duck class modified to use behaviors?
A: Adds two fields: FlyBehavior flyBehavior; QuackBehavior quackBehavior; New methods: performFly() → Delegates to flyBehavior.fly() performQuack() → Delegates to quackBehavior.quack() Key Idea: "Ducks delegate behavior instead of implementing it."
26
Flashcard 5 (Delegation vs Inheritance - Page 15) Q: Contrast delegation (new design) with inheritance (old design).
A: Inheritance (Old) Delegation (New) Behaviors in superclass/subclass Behaviors in separate classes Hard to change at runtime Swappable via setters Tight coupling Loose coupling to interfaces
27
Flashcard 6 (MallardDuck Setup - Page 16) Q: How is MallardDuck configured in its constructor?
A: public MallardDuck() { quackBehavior = new Quack(); // Normal quack flyBehavior = new FlyWithWings(); // Can fly } Why This Works: Assigns concrete behaviors at instantiation but still programs to interfaces.
28
Flashcard 7 (Initialization Critique - Page 17) Q: What’s the flaw in initializing behaviors in constructors?
A: Violates "program to interfaces": flyBehavior = new FlyWithWings(); // Still depends on concrete class! Solution Hint: Dependency Injection (later patterns will fix this).
29
Flashcard 8 (Behavior Reuse - Page 13) Q: How does this design enable behavior reuse?
A: Shared instances: All ducks that Quack use the same Quack class. No duplicate code in subclasses. Example: MallardDuck and RedheadDuck share FlyWithWings.
30
Flashcard 9 (Testing the Code - Page 18-19) Q: What’s the output of MiniDuckSimulator’s first test?
A: Quack I'm flying!! How It Works: mallard.performQuack() → Quack.quack() mallard.performFly() → FlyWithWings.fly()
31
Flashcard 10 (Key Advantage - Page 14 QA) Q: How does this design support adding FlyRocketPowered later?
A: Create new class: public class FlyRocketPowered implements FlyBehavior { public void fly() { /* rocket logic */ } } No changes to Duck or existing ducks required!
32
Flashcard 11 (State in Behaviors - Page 14 QA) Q: Can behavior classes have state? Give an example.
A: Yes! Example: FlyWithWings could track: wingFlapsPerMinute maxAltitude Key Idea: Behaviors are full classes (not just methods), so they can encapsulate data.
33
Flashcard 12 (Non-Duck Users - Page 14 Exercise) Q: What non-duck class might use QuackBehavior?
A: Duck call device (hunting tool that mimics quacks). Why It Works: Reuses quack algorithms without inheriting from Duck.
34
Summary Diagram
Summary Diagram Duck (abstract) │ ├─ flyBehavior: FlyBehavior ├─ quackBehavior: QuackBehavior │ └─ MallardDuck (assigns FlyWithWings/Quack) Golden Rule: "Delegation > Inheritance"
35
Flashcard 1 (Dynamic Behavior Setup - Page 20) Q: What two methods are added to Duck to enable runtime behavior changes?
A: public void setFlyBehavior(FlyBehavior fb) { flyBehavior = fb; } public void setQuackBehavior(QuackBehavior qb) { quackBehavior = qb; } Key Feature: Behaviors can be swapped at runtime without modifying duck classes.
36
Flashcard 2 (ModelDuck Initialization - Page 20) Q: How is ModelDuck configured initially, and why?
A: public ModelDuck() { flyBehavior = new FlyNoWay(); // Can't fly by default quackBehavior = new Quack(); // But can quack } Purpose: Demonstrates a duck with default limitations that can be upgraded later.
37
Flashcard 3 (Rocket-Powered Upgrade - Page 20-21) Q: How does the ModelDuck gain rocket-powered flight?
A: Define new behavior: public class FlyRocketPowered implements FlyBehavior { public void fly() { System.out.println("I'm flying with a rocket!"); } } Upgrade at runtime: model.setFlyBehavior(new FlyRocketPowered());
38
Flashcard 4 (Test Output - Page 21) Q: What is the output of the dynamic behavior test?
A: I can't fly // Initial FlyNoWay I'm flying with a rocket! // After setFlyBehavior() Proves: Behaviors are truly dynamic (not compile-time locked).
39
Flashcard 5 (Design Principle Applied - Page 21) Q: Which design principle does dynamic behavior change exemplify?
A: "Favor composition over inheritance" Behaviors are composed at runtime (not inherited). Contrast: Inheritance would require subclassing (e.g., RocketPoweredModelDuck).
40
Flashcard 6 (Key Advantage - Page 21) Q: Why is this approach better than overriding methods?
A: No subclass explosion: Avoids classes like RubberDuckNoFly, ModelDuckRocket, etc. Flexibility: Change behaviors on the fly (even mid-simulation).
41
Flashcard 7 (Real-World Analogy - Page 21) Q: How is this like upgrading a car’s engine?
A: Inheritance Approach: Buy a new car (subclass). Strategy Pattern: Swap engines (behaviors) dynamically.
42
Flashcard 8 (Limitation Addressed - Page 21) Q: How does this fix the constructor initialization issue from Page 17?
A: Constructors hardcode behaviors. Setters allow post-creation changes.
42
Flashcard 9 (Testing Scenario - Page 21) Q: What three steps does MiniDuckSimulator demonstrate?
A: Create ModelDuck (can’t fly). Call performFly() → FlyNoWay. Upgrade to FlyRocketPowered and retest.
43
Flashcard 10 (Open/Closed Principle - Implied) Q: How does this align with the Open/Closed Principle?
A: Open: Add FlyRocketPowered without modifying ModelDuck. Closed: Duck class remains unchanged for new behaviors.
43
Visual Summary
[ModelDuck] --(initial)--> [FlyNoWay] | |-- setFlyBehavior() --> [FlyRocketPowered] Key Takeaway: "Encapsulate behaviors and make them interchangeable." Let me know if you’d like flashcards for the final pattern definition or class diagram!
44
Flashcard 1 (Formal Definition) Q: What is the textbook definition of the Strategy Pattern?
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." Key Phrases: Family of algorithms → FlyBehavior, QuackBehavior Encapsulates each → Separate behavior classes Interchangeable → Dynamic switching via setters
45
Flashcard 2 (Duck Simulation Example) Q: How does the duck simulator exemplify this definition?
A: Family of algorithms: Fly: FlyWithWings, FlyNoWay, FlyRocketPowered Quack: Quack, Squeak, MuteQuack Encapsulation: Each behavior is a separate class. Interchangeable: setFlyBehavior() swaps implementations at runtime.
45
Flashcard 3 (Client Independence) Q: How does the pattern ensure algorithms vary independently from clients?
A: Ducks (clients) depend only on FlyBehavior/QuackBehavior interfaces. Changes to behaviors (e.g., new FlyRocketPowered) require no Duck class modifications. Code Proof: // Duck class never changes when adding: public class FlyRocketPowered implements FlyBehavior { ... }
46
Flashcard 4 (Design Principles Recap) Q: Which three design principles underlie the Strategy Pattern?
A: Encapsulate what varies → Separate fly/quack behaviors. Program to interfaces → Depend on FlyBehavior, not FlyWithWings. Favor composition → Ducks have behaviors (HAS-A). Hierarchy: Duck (client) │ ├─ FlyBehavior (interface) │ ├─ FlyWithWings │ └─ FlyNoWay │ └─ QuackBehavior (interface) ├─ Quack └─ Squeak
47
Flashcard 5 (Real-World Analogy) Q: Give a non-duck example of the Strategy Pattern.
A: Payment Processing: Algorithms: Credit Card, PayPal, Crypto Context: Checkout system Swappable: Payment method can change without modifying checkout code. Match to Definition: Family: Payment algorithms Encapsulated: Each in separate classes Interchangeable: User selects method at runtime.
48
Flashcard 6 (Pattern vs. Ad-Hoc Solution) Q: Contrast Strategy Pattern with the initial inheritance approach.
A: Strategy Pattern Inheritance Approach Behaviors encapsulated Behaviors baked into hierarchy Easy to add new behaviors Requires subclass explosion Changes don’t ripple Risk of unintended side effects Example: Adding FlyRocketPowered: Strategy: One new class, no Duck changes. Inheritance: New subclass(es), risk breaking existing ducks.
49
Flashcard 7 (Implementation Checklist) Q: What steps are needed to implement the Strategy Pattern?
A: Identify varying behaviors (e.g., fly/quack). Define interface for each behavior family. Create concrete behavior classes. Delegate behavior calls in context class (e.g., Duck). (Optional) Add setters for dynamic changes. Duck Example: Step 2: FlyBehavior interface Step 3: FlyWithWings, FlyNoWay Step 4: Duck.performFly()
50
Flashcard 8 (Benefits Summary) Q: List three key advantages of the Strategy Pattern.
A: Eliminates conditional logic: No if (duckType == RUBBER) ... checks. Open/Closed Principle: New behaviors without modifying clients. Runtime flexibility: Behaviors can be swapped dynamically. Trade-off: Increased number of classes (but better organization).
51
Flashcard 9 (Pattern Identification) Q: How would you recognize a Strategy Pattern in existing code?
A: Look for: Interface + multiple implementations (e.g., FlyBehavior → FlyWithWings). Delegation: Context class (e.g., Duck) calls behavior.method(). Polymorphic assignments: flyBehavior = new FlyRocketPowered().
52
Mnemonic for Strategy Pattern
S.T.R.A.T.E.G.Y: Separate behaviors Target interfaces Runtime swaps Algorithm families Trivial extensions Encapsulate variation Generic clients Yagni (You Aren’t Gonna Need inheritance)
53
Flashcard 10 (Anti-Pattern Warning) Q: What’s a common misuse that isn’t the Strategy Pattern?
A: God objects: Putting all behavior variations in one class with switch statements. Example (BAD): class Duck { void fly() { if (type == RUBBER) /* do nothing */ else if (type == MALLARD) /* wing flapping */ } } Why It Fails: Violates "encapsulate what varies" and "program to interfaces."
54
Where we use this strategy patterns?
1. Behavioral Flexibility When: A system needs multiple algorithms for a task (e.g., different fly/quack behaviors). Example: Payment processing (Credit Card, PayPal, Crypto). Navigation apps (Driving, Walking, Public Transport routes). 2. Avoiding Conditional Complexity When: You’d otherwise use switch/if-else to select behaviors. Example: File compression (ZIP, RAR, 7z algorithms). Image filters (Blur, Sharpen, Grayscale). 3. Runtime Behavior Changes When: Objects must alter behavior dynamically. Example: Game characters switching weapons/tools. UI themes (Light/Dark mode toggling). 4. Legacy System Modernization When: Extending old code without breaking it. Example: Adding new encryption methods to a security module. 5. Testing Isolation When: Mocking dependencies in unit tests. Example: Replacing a real database call with a mock data fetcher. Key Signs You Need Strategy Pattern Multiple variants of a behavior exist. Behaviors change frequently or need hot-swapping. You want to avoid subclass explosion. SimUDuck Alignment: Fly/quack behaviors matched all these criteria! Real-World Frameworks Using Strategy Java’s Comparator: Sort collections with different strategies. React’s State Management: Plugable state update logic. AWS SDKs: Configurable HTTP client implementations. Anti-Patterns (When NOT to Use) Only one immutable behavior exists. Behaviors are trivial (e.g., simple if-else suffices). Overhead outweighs benefits (e.g., micro-optimizations). Mnemonic: "VARIABLE" Vary algorithms Avoid inheritance locks Runtime swaps Interface-driven Anti-conditional Behavior encapsulation Low coupling Extensible Let me know if you'd like concrete code examples for any scenario!
55
Ex1
Here’s a **hands-on exercise** to test your understanding of the Strategy Pattern, inspired by the SimUDuck example but with a fresh twist: --- **Exercise: "ZooBot" Simulator** You’re building a robot zoo simulator where each robot animal has **movement** and **sound** behaviors. Some robots can walk, others roll, and some hover. Sounds vary from beeps to roars. **Step 1: Identify Varying Behaviors** List the behaviors that change across robot animals: 1. **Movement**: - `Walk` (for robot lions) - `Roll` (for robot spheres) - `Hover` (for drone birds) 2. **Sound**: - `Beep` (generic robots) - `Roar` (predator bots) - `Chirp` (bird bots) **Step 2: Define Behavior Interfaces** Write Java/Kotlin/Python interfaces: ```java public interface MoveBehavior { void move(); } public interface SoundBehavior { void makeSound(); } ``` **Step 3: Implement Concrete Behaviors** Create classes for each behavior. Example: ```java public class Hover implements MoveBehavior { @Override public void move() { System.out.println("Zooming through the air!"); } } ``` **Step 4: Design the `RobotAnimal` Class** Structure the base class with delegation: ```java public abstract class RobotAnimal { MoveBehavior moveBehavior; SoundBehavior soundBehavior; public void performMove() { moveBehavior.move(); } public void performSound() { soundBehavior.makeSound(); } // Add setter methods for dynamic changes! } ``` **Step 5: Create Concrete Robots** Example: `RobotLion`: ```java public class RobotLion extends RobotAnimal { public RobotLion() { moveBehavior = new Walk(); soundBehavior = new Roar(); } } ``` **Step 6: Test Dynamic Behavior** Add a `RobotDroneBird` that can switch from `Chirp` to `Mute` sound: ```java RobotDroneBird drone = new RobotDroneBird(); // Default: Chirp drone.performSound(); // "Chirp chirp!" drone.setSoundBehavior(new Mute()); drone.performSound(); // (Silence) ``` --- **Challenge Questions** 1. How would you add a `JetPack` movement behavior without modifying existing robots? 2. What happens if a `RobotFish` needs a `Swim` behavior? Is this a breaking change? 3. **Anti-Pattern Alert**: If someone suggests putting all behaviors in the `RobotAnimal` superclass with `if-else`, why is that bad? --- **Solution Sketch** 1. **Add `JetPack`**: ```java public class JetPack implements MoveBehavior { public void move() { System.out.println("Fwoosh!"); } } ``` No other classes need updates! 2. **`RobotFish`**: - Just create `Swim` class implementing `MoveBehavior`. - **Not breaking**: Existing robots ignore this new behavior. 3. **Anti-Pattern**: - Violates **Open/Closed Principle** (modify superclass for changes). - Creates **tight coupling** (all behaviors in one class). --- **Bonus: UML Diagram** Sketch the class diagram with: - `RobotAnimal` (client) - `MoveBehavior` and `SoundBehavior` (strategies) - Arrows for **HAS-A** (composition) and **IMPLEMENTS**. --- Submit your code and answers, and I’ll play the role of the "compiler" to give feedback! 🚀
56
cont
Great start! Here’s a refined version of your code with corrections and enhancements to fully implement the Strategy Pattern for the `RobotAnimal` simulator: --- **Refined Solution with Fixes** **1. Behavior Interfaces (Perfect!)** ```java interface Movement { void move(); // Note: Removed redundant 'public' (interfaces imply public) } interface Sound { void sound(); } ``` **2. Concrete Behavior Implementations** ```java // Movement behaviors class Walk implements Movement { public void move() { // Added parentheses () System.out.println("Walking on treads..."); } } class Roll implements Movement { public void move() { System.out.println("Rolling on wheels..."); } } class Hover implements Movement { public void move() { System.out.println("Hovering with fans..."); } } // Sound behaviors class Beep implements Sound { public void sound() { System.out.println("Beep beep!"); } } class Roar implements Sound { public void sound() { System.out.println("ROAR!"); } } class Chirp implements Sound { // Fixed typo ("Chrip" → "Chirp") public void sound() { System.out.println("Chirp chirp!"); } } ``` **3. Abstract `RobotAnimal` Class (Key Fixes)** ```java abstract class RobotAnimal { Movement moveBehavior; // Renamed for clarity (matches Strategy Pattern naming) Sound soundBehavior; // No need for empty constructor (Java provides default) public void performMove() { // Renamed to match Duck example's 'performX()' style moveBehavior.move(); } public void performSound() { soundBehavior.sound(); } // Setters for dynamic behavior changes public void setMoveBehavior(Movement mb) { // Fixed parameter type (capitalized) this.moveBehavior = mb; } public void setSoundBehavior(Sound sb) { this.soundBehavior = sb; } } ``` **4. Concrete Robot: `Lion` (Fixed Syntax)** ```java class RobotLion extends RobotAnimal { // Renamed for clarity RobotLion() { moveBehavior = new Walk(); soundBehavior = new Roar(); } // Removed direct calls in class body (invalid syntax) // Calls will happen via performMove()/performSound() } ``` **5. Testing the Implementation** ```java public class ZooBotSimulator { public static void main(String[] args) { RobotLion lion = new RobotLion(); lion.performMove(); // Output: "Walking on treads..." lion.performSound(); // Output: "ROAR!" // Dynamic behavior change lion.setMoveBehavior(new Hover()); lion.performMove(); // Now: "Hovering with fans..." } } ``` --- **Key Improvements** 1. **Fixed Syntax Errors**: - Added parentheses to `move()` and `sound()` methods. - Corrected `setMoveBehavior` parameter type (`Movement` instead of `move`). 2. **Consistency with Strategy Pattern**: - Renamed `move`/`sound` → `moveBehavior`/`soundBehavior` (matches `FlyBehavior`/`QuackBehavior` from SimUDuck). - Used `performMove()`/`performSound()` to mirror `performFly()`/`performQuack()`. 3. **Removed Invalid Code**: - Deleted `move.makeMovement();` inside `Lion` class (methods should be called on instances, not in class body). 4. **Added Test Case**: - Demonstrated dynamic behavior change (lion switches from walking to hovering). --- **Exercise for You** 1. **Add a `RobotDroneBird` class** that: - Starts with `Hover` and `Chirp`. - Can switch to `MuteSound` (new behavior you’ll create). 2. **Implement `JetPack` Movement**: ```java class JetPack implements Movement { public void move() { System.out.println("Flying with jet propulsion!"); } } ``` Test it by upgrading your `RobotLion`’s movement at runtime. 3. **Anti-Pattern Check**: - Why is this better than putting `if (type == LION) roar();` in `RobotAnimal`? --- **Answer Key (For Self-Check)** 1. **`RobotDroneBird`**: ```java class RobotDroneBird extends RobotAnimal { RobotDroneBird() { moveBehavior = new Hover(); soundBehavior = new Chirp(); } } ``` ```java class MuteSound implements Sound { public void sound() { System.out.println("(Silent mode)"); } } ``` 2. **Dynamic JetPack Test**: ```java RobotLion lion = new RobotLion(); lion.setMoveBehavior(new JetPack()); lion.performMove(); // "Flying with jet propulsion!" ``` 3. **Anti-Pattern Answer**: - **Violates Open/Closed Principle**: Adding a new robot type requires modifying `RobotAnimal`. - **Tight Coupling**: All behaviors are tangled in one class. - **No Runtime Flexibility**: Can’t change behaviors dynamically. --- Your original structure was very close—just needed minor polishing! Try extending it further with the exercise. 🚀 Here's the **optimized and corrected version** of your RobotAnimal implementation with explanations for each improvement: Final Corrected Implementation ```java // Behavior Interfaces interface Movement { void move(); } interface Sound { void makeSound(); // Changed to makeSound() for consistency } // Movement Behaviors class Walk implements Movement { public void move() { System.out.println("Walking on treads..."); } } class Roll implements Movement { public void move() { System.out.println("Rolling on wheels..."); } } class Hover implements Movement { public void move() { System.out.println("Hovering with fans..."); } } // Sound Behaviors class Beep implements Sound { public void makeSound() { // Changed to match interface System.out.println("Beep beep!"); } } class Roar implements Sound { public void makeSound() { System.out.println("ROAR!"); } } class Chirp implements Sound { public void makeSound() { System.out.println("Chirp chirp!"); } } abstract class RobotAnimal { protected Movement moveBehavior; // Made protected for subclass access protected Sound soundBehavior; public void performMove() { if (moveBehavior != null) { // Added null check moveBehavior.move(); } } public void performSound() { if (soundBehavior != null) { soundBehavior.makeSound(); } } public void setMoveBehavior(Movement mb) { this.moveBehavior = mb; } public void setSoundBehavior(Sound sb) { this.soundBehavior = sb; } } class RobotLion extends RobotAnimal { RobotLion() { moveBehavior = new Walk(); soundBehavior = new Roar(); } // Removed redundant overrides - inherited methods work fine } class RobotBird extends RobotAnimal { RobotBird() { moveBehavior = new Hover(); soundBehavior = new Chirp(); } } ``` Key Improvements: 1. **Consistent Method Naming**: - Changed `sound()` to `makeSound()` in the Sound interface and implementations for better clarity 2. **Removed Redundant Overrides**: - Deleted the overridden `performMove()` and `performSound()` in `RobotLion` since they didn't add any new functionality 3. **Added Null Checks**: - Protected against NullPointerException in behavior methods 4. **Added New Robot Type**: - Included `RobotBird` to demonstrate multiple robot types 5. **Access Modifiers**: - Made behavior fields protected for better subclass access while maintaining encapsulation 6. **Fixed Potential Bugs**: - Ensured all interface methods are properly implemented - Standardized naming conventions Example Usage: ```java public class ZooSimulator { public static void main(String[] args) { RobotAnimal lion = new RobotLion(); lion.performMove(); // "Walking on treads..." lion.performSound(); // "ROAR!" RobotAnimal bird = new RobotBird(); bird.performMove(); // "Hovering with fans..." bird.performSound(); // "Chirp chirp!" // Dynamic behavior change lion.setMoveBehavior(new Hover()); lion.performMove(); // Now: "Hovering with fans..." } } ``` Why This is Better: 1. **True Strategy Pattern Implementation**: - Behaviors are fully encapsulated and interchangeable - New behaviors can be added without modifying existing code 2. **More Robust**: - Null checks prevent crashes - Clear method naming reduces confusion 3. **Easier to Extend**: - Adding new robot types is trivial - Behaviors can be mixed and matched 4. **Consistent with Principles**: - Open/Closed Principle (open for extension, closed for modification) - Single Responsibility Principle (each class has one purpose) This implementation now perfectly demonstrates the Strategy Pattern while being more robust and maintainable than the original version.
57
ex2
Here's a **new exercise** to deepen your understanding of the Strategy Pattern with a fresh scenario: --- **Exercise: "SmartHome" Device Controller** You're building a smart home system where various devices (lights, thermostat, security camera) can have different **modes** (e.g., home/away/vacation) that change their behavior. **Part 1: Identify Behaviors** 1. **Device Actions**: - Lights: `turnOn()`, `turnOff()`, `dim()` - Thermostat: `setTemperature()`, `energySave()` - SecurityCamera: `startRecording()`, `motionAlert()` 2. **Mode Strategies**: - `HomeMode`: Normal operation - `AwayMode`: Energy-saving, security-focused - `VacationMode`: Random light activity, strict security **Part 2: Implement the Pattern** 1. **Create Interfaces**: ```java interface ModeStrategy { void execute(Light light, Thermostat thermo, SecurityCamera camera); } ``` 2. **Concrete Strategies**: ```java class HomeMode implements ModeStrategy { public void execute(Light l, Thermostat t, SecurityCamera c) { l.turnOn(); t.setTemperature(22); c.startRecording(); } } class AwayMode implements ModeStrategy { public void execute(Light l, Thermostat t, SecurityCamera c) { l.turnOff(); t.energySave(); c.motionAlert(); } } ``` 3. **Context Class**: ```java class SmartHomeController { private ModeStrategy currentMode; public void setMode(ModeStrategy mode) { this.currentMode = mode; } public void executeMode(Light l, Thermostat t, SecurityCamera c) { currentMode.execute(l, t, c); } } ``` **Part 3: Your Tasks** 1. **Complete `VacationMode`**: - Lights: Randomly turn on/off every 2 hours - Thermostat: Set to 18°C - Camera: Enable motion alerts + continuous recording 2. **Add a New Device**: - SmartLock: `lock()`, `unlock()` - Update all modes to handle it. 3. **Dynamic Mode Switching**: - Simulate a family leaving home: ```java controller.setMode(new AwayMode()); ``` **Challenge Questions** 1. How would weather data (e.g., extreme cold) temporarily override `AwayMode` thermostat settings? 2. What if devices need different behaviors per room? 3. **Anti-Pattern Check**: Why shouldn't modes be implemented as device subclasses (e.g., `AwayModeLight`)? --- **Solution Sketch** 1. **VacationMode**: ```java class VacationMode implements ModeStrategy { public void execute(Light l, Thermostat t, SecurityCamera c) { new Timer().scheduleAtFixedRate(new TimerTask() { public void run() { l.toggle(); // Alternate on/off } }, 0, 2 * 60 * 60 * 1000); // 2-hour intervals t.setTemperature(18); c.motionAlert(); c.startRecording(); } } ``` 2. **Weather Override**: - Create a `WeatherAwareDecorator` that wraps `ModeStrategy` and adjusts temperatures. 3. **Per-Room Behaviors**: - Use a `Map` in `SmartHomeController`. 4. **Anti-Pattern Answer**: - Leads to **class explosion** (e.g., `HomeModeLight`, `AwayModeLight`, etc.) - **Violates SRP**: Devices would need to know about modes. - **No runtime flexibility**: Can't switch modes without recreating devices. --- **Key Concepts Tested** 1. **Strategy Composition**: Multiple devices share mode strategies. 2. **Runtime Changes**: Dynamic mode switching. 3. **Open/Closed Principle**: Adding new modes/devices without breaking old code. Try implementing this and share your code for review! 🏠💡