210 likes | 329 Views
The Strategy Pattern. CSC 211: Design Patterns. Reading Quiz. Video Game Example. Aliens vs. Humans Both have adjustable life points Both take damage Both can recover life points Let’s design a class… Some functionality is shared, so inheriting from a common superclass makes sense
E N D
The Strategy Pattern CSC 211: Design Patterns
Video Game Example • Aliens vs. Humans • Both have adjustable life points • Both take damage • Both can recover life points • Let’s design a class… • Some functionality is shared, so inheriting from a common superclass makes sense • We’ll differentiate between the two classes in their subclasses
Class name LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Class variables Class methods
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void extends Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int <<create>> = constructor What does Human inherit from LifeForm? What does Human add to extend its superclass?
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Alien <<create>> Alien() Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int So we’re all set … at least for handling life points, right?
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Alien <<create>> Alien() Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int Design change! Characters allowed to recover life points over time
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void recover(i : int) : void Alien <<create>> Alien() Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int • New Problem: • Now Humans have a double advantage (armor + recovery)
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Alien <<create>> Alien() recover(i : int) : void Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int • Another Design Change: • Some aliens should be harder than others • They should recover at different rates, not all at once
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int Alien maxLifePoints : int <<create>> Alien() recoverNone(i : int) : void recoverFraction(percent : double) void recoverLinear(i : int) : void • Possible Solution: • Multiple methods • Problems with this?
Design Principle #1 You will spend more time maintaining your code than you will on the initial design. Plan for change! Identify the aspects of your application that vary and separate them from what stays the same
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int Alien maxLifePoints : int <<create>> Alien() recoverNone(i : int) : void recoverFraction(percent : double) void recoverLinear(i : int) : void Create an interface for the things that vary
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int Alien maxLifePoints : int <<create>> Alien() RecoveryBehavior calculateRecovery(current : int,max : int) : int <<interface>> Create an interface for the things that vary
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int Alien maxLifePoints : int <<create>> Alien() RecoveryBehavior calculateRecovery(current : int,max : int) : int <<interface>> Create an interface for the things that vary Create behavior classes that implement the interface
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void <<interface>> RecoveryBehavior calculateRecovery(current : int,max : int) : int Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int RecoveryLinear step : int <<create>> RecoveryLinear(rStep : int) calculateRecovery(current : int, max : int) : int RecoveryFractional percent : double <<create>> RecoveryFractional(rPercent : double) calculateRecovery(current : int, max : int) : int RecoveryNone <<create>> RecoveryNone() calculateRecovery(current : int, max : int) : int Alien maxLifePoints : int <<create>> Alien() implements
Design Principle #2 Exploit polymorphism in useful ways. You can only inherit from one superclass Program to an interface, not an implementation
LifeForm currentLifePoints : int getLifePoints() : int takeHit(i : int): void <<interface>> RecoveryBehavior calculateRecovery(current : int,max : int) : int Human armorPoints : int <<create>> Human(life : int,armor : int) setArmorPoints(armor : int) : void getArmorPoints() : int RecoveryLinear step : int <<create>> RecoveryLinear(rStep : int) calculateRecovery(current : int, max : int) : int RecoveryFractional percent : double <<create>> RecoveryFractional(rPercent : double) calculateRecovery(current : int, max : int) : int Has-A Alien recoveryBehavior : RecoveryBehavior maxLifePoints : int <<create>> Alien() recover() : void setCurrentLifePoints(i : int) : void RecoveryNone <<create>> RecoveryNone() calculateRecovery(current : int, max : int) : int
Design Principle #3 Avoid inheritingbehavior Favors flexibility Favor composition over inheritance
The Strategy Pattern SuperClass Behavior myBehavior methodA() methodB() <<interface>> Behavior behaviorMethod() HAS-A Implements (also IS-A) IS-A SubClassA methodA() <<override>> Behavior_v1 behaviorMethod() SubClassB Behavior_v2 behaviorMethod()
The Strategy Pattern Definition The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
Lab 2 • Due Monday • Submit your code and tests electronically • Header the at top of every file you write /** * Description of this class * @author Your Full Name * Your section number */ • ProjectName_LastName • Zip you eclipse project, name your zip file • LastName_Lab#