refactoring ii dealing with polymorphism. switch in rental switches on movie! class rental …...

32
Refactoring II Refactoring II Dealing with Polymorphism Dealing with Polymorphism

Upload: raymond-lane

Post on 17-Jan-2016

212 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Refactoring IIRefactoring II

Dealing with PolymorphismDealing with Polymorphism

Page 2: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Switch in Rental Switches on Switch in Rental Switches on Movie!Movie!

class Rental …public double getCharge(){double result = 0;switch (getMovie().getPriceCode()){ case Movie.REGULAR: result += 2; if (getDaysRented()>2) result += (getDaysRented()-2)*1.5; break; case Movie.NEWRELEASE: result += getDaysRented()*3; break; case Movie.CHILDRENS: result += 1.5; if (getDaysRented()-3)*1.5; break; }return result;}

Page 3: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

So Put It In MovieSo Put It In Movieclass Movie …public double getCharge(int daysRented){double result = 0;switch (getPriceCode(){ case Movie.REGULAR: result += 2; if (getDaysRented()>2) result += (getDaysRented()-2)*1.5; break; case Movie.NEWRELEASE: result += getDaysRented()*3; break; case Movie.CHILDRENS: result += 1.5; if (getDaysRented()-3)*1.5; break; }return result;}

Page 4: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

RemarksRemarks

• This needs data from RentalThis needs data from Rental• So make it an int parameter daysRented So make it an int parameter daysRented

instead of a call getDaysRented()instead of a call getDaysRented()• Leave the type of Movie alone for nowLeave the type of Movie alone for now

A good candidate for polymorphismA good candidate for polymorphism This type of information is more volatile, i.e. This type of information is more volatile, i.e.

subject to changesubject to change

Page 5: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Change getCharge on RentalChange getCharge on Rental

class Rental …public double getCharge(){ return _movie.getCharge(_daysRented):}

Page 6: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Similar for Similar for getFrequentRenterPoints()getFrequentRenterPoints()

• Move it from Rental to MovieMove it from Rental to Movie

• Details not shown (exercise)Details not shown (exercise)

class Rental … int getFrequentRenterPoints(){ if((getMovie().getPriceCode()== Movie.NEW_RELEASE) && getDaysRented() > 1) return 2 else return 1;

Page 7: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

ProblemProblem

• Movie data used in switch statementMovie data used in switch statement• Fix it with inheritance and polymorphismFix it with inheritance and polymorphism• Not possible since child type can change Not possible since child type can change

over the movie class’s lifetimeover the movie class’s lifetime• So, use state/strategy patternSo, use state/strategy pattern

Page 8: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

The State PatternThe State Pattern

Context State

ConcreteStateA ConcreteStateB

state.handle()

handle()

handle()handle()

request

Page 9: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

State PatternState Pattern

• Behavior is encapsulated in the concrete Behavior is encapsulated in the concrete state objectsstate objects

• Context delegates to one of the statesContext delegates to one of the states• It appears that the state class is changingIt appears that the state class is changing

But in reality it is just changing its behaviorBut in reality it is just changing its behavior

• Change behavior by composing with a Change behavior by composing with a different objectdifferent object

Page 10: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

State PatternState Pattern

• ContextContext: The class with the internal states: The class with the internal states• StateState: The common interface for all : The common interface for all

concrete statesconcrete states• ConcreteStatesConcreteStates: deal with requests from : deal with requests from

the context. Each provides own the context. Each provides own implementation for the requestimplementation for the request

• When Context changes state so will the When Context changes state so will the concrete state’s behaviorconcrete state’s behavior

Page 11: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

We changeWe change

Page 12: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

ToTo

Replace Type Code with State/Strategy

Page 13: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Step 1: ensure fields accessed Step 1: ensure fields accessed by by getget and and setset

• Work on constructor in Work on constructor in moviemovie• Use Self Use Self Encapsulate FieldEncapsulate Field

class Movie{ …public Movie (String name, int priceCode){ _title = name; setPriceCode(priceCode);}

}

Self Encapsulate Field

Page 14: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Why encapsulate data access?Why encapsulate data access?

• If a datum is accessed in a base class, but If a datum is accessed in a base class, but you want to compute a different value from you want to compute a different value from this in a child.this in a child.

• If this is encapsulated, you can override the If this is encapsulated, you can override the accessors to change the value.accessors to change the value.

• See See Self Encapsulate FieldSelf Encapsulate Field

Page 15: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Step 2: Add new classesStep 2: Add new classes

abstract class Price{ abstract int getPriceCode();}class ChildrensPrice extends Price{ public int getPriceCode(){return Movie.CHILDRENS;}}class NewReleasePrice extends Price{ public int getPriceCode(){return Movie.NEW_RELEASE;}}Class RegularPrice extends Price{ public int getPriceCode(){return Movie.REGULAR;}}

Page 16: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Step 3: Change Step 3: Change getget and and setset in in Movie classMovie class

• Change the accessorsChange the accessors

class Movie{…private Price _price;public int getPriceCode(){return _price.getPriceCode;}public void setPriceCode(int arg){ switch(arg){ case REGULAR: _price = new RegularPrice(); break; case CHILDRENS: _price = new ChildrensPrice();break; case NEW_RELEASE: _price = new NewReleasePrice(); break; }…}

Page 17: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Step 4 Move Step 4 Move getChargegetCharge to to PricePrice

class Price{…public double getCharge(int daysRented){ double result = 0.0; switch (getPriceCode()){ case Movie.REGULAR: result += 2; if (daysRented > 2) result += (daysRented–2)*1.5; break; case Movie.NEW_RELEASE: result += daysRented*3; break; case Movie.CHILDRENS: result += 1.5; if (daysRented>3) result += (daysRented-3)*1.5; break; } return result;}

Move Method

Page 18: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Don’t forget you need it in Don’t forget you need it in MovieMovie

class Movie{… double getCharge(int daysRented){ return _price.getCharge(daysRented); }…}

Page 19: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Get rid of the switchGet rid of the switch

Page 20: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Do a Do a getCharge()getCharge() in class in class RegularPriceRegularPrice

class RegularPrice{… double getCharge(int daysRented){ double result = 2.0; if (daysRented>2) result += (daysRented-2)*1.5; return result; }…}

Page 21: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Don’t forget to compile and testDon’t forget to compile and test

Replace Conditional With Polymorphism

Page 22: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Now same for Now same for ChildrensPriceChildrensPrice

class ChildrensPrice{… double getCharge(int daysRented){ double result = 1.5; if (daysRented > 3) result += (daysRented-3)*1.5; return result; }…}

Page 23: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

And finally And finally NewReleasePriceNewReleasePrice

class NewReleasePrice{… double getCharge(int daysRented){ return daysRented*3; }…}

Page 24: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Finally get rid of the old Finally get rid of the old getChargegetCharge

class Price{… abstract double getCharge(int daysRented);…}

Page 25: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Do the same to Do the same to getFrequentRenterPointsgetFrequentRenterPoints

class Movie{… int getFrequentRenterPoints(int daysRented){ return _price.getFrequentRenterPoints(daysRented);…}

Class Price{… int getFrequentRenterPoints(int daysRented){ if ((getPriceCode()==Movie.NEW_RELEASE)&& daysRented >1) return 2; else return 1;}

Page 26: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Now Override to Now Override to NewReleasePriceNewReleasePrice

class NewReleasePrice{… int getFrequentRenterPoints(int daysRented){ return (daysRented>1)?2:1;}

And keep a defined method on superclass Price

Class Price{… int getFrequentRenterPoints(int daysRented){ return 1; }…}

Page 27: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

When do I refactor?When do I refactor?

““If it stinks change it”If it stinks change it”

Page 28: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Hence the Name: Code SmellingHence the Name: Code Smelling

Page 29: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

Code SmellsCode Smells

• Duplicated CodeDuplicated Code• Long MethodLong Method• Large ClassLarge Class• Long Parameter ListLong Parameter List• Divergent ChangeDivergent Change• Shotgun SurgeryShotgun Surgery

Page 30: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

More Code SmellsMore Code Smells

• Feature EnvyFeature Envy• Data ClumpsData Clumps• Primitive ObsessionPrimitive Obsession• Switch StatementSwitch Statement• Parallel Inheritance HierarchyParallel Inheritance Hierarchy• Lazy ClassLazy Class

Page 31: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

And Even MoreAnd Even More

• Speculative GeneralitySpeculative Generality• Temporary FieldTemporary Field• Message ChainsMessage Chains• Middle ManMiddle Man• Inappropriate IntimacyInappropriate Intimacy• Incomplete Library ClassIncomplete Library Class

Page 32: Refactoring II Dealing with Polymorphism. Switch in Rental Switches on Movie! class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){

And FinallyAnd Finally

• Data ClassData Class• CommentsComments• Refused BequestRefused Bequest• And Many MoreAnd Many More