Where Were We? Where Were We? • Attempting to spray ants with ant Attempting to spray ants with ant poison and (generic) insects with poison and (generic) insects with generic spray generic spray • If there is not a complete match If there is not a complete match between the signatures of methods in between the signatures of methods in base and derived classes there is no base and derived classes there is no polymorphism polymorphism • Compiler determines the call by using Compiler determines the call by using the declared type the declared type • Now apply this Now apply this
31
Embed
Where Were We? Attempting to spray ants with ant poison and (generic) insects with generic spray Attempting to spray ants with ant poison and (generic)
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Where Were We?Where Were We?
• Attempting to spray ants with ant poison and Attempting to spray ants with ant poison and (generic) insects with generic spray(generic) insects with generic spray
• If there is not a complete match between the If there is not a complete match between the signatures of methods in base and derived signatures of methods in base and derived classes there is no polymorphismclasses there is no polymorphism
• Compiler determines the call by using the Compiler determines the call by using the declared typedeclared type
• Now apply thisNow apply this
public class Poison{ public void spray(Insect aBug){ System.out.println(“Generic Spray”); } public void spray(Ant antBug){ System.out.println(“Generic Ant Spray”); }};
public class AntPoison extends Poison{ public void spray(Ant antBug){ System.out.println(“Spraying Ant with Ant spray”); }};
RemarksRemarks
• It appears that we are attempting to use It appears that we are attempting to use polymorphism polymorphism bothboth on the on the PoisonPoison type type andand the the InsectInsect type type
• The only polymorphism that will work is with The only polymorphism that will work is with a static reference to a static reference to PoisonPoison (and a run-time (and a run-time reference to either reference to either PoisonPoison or or AntPoisonAntPoison) ) and a static reference to and a static reference to AntAnt. Period. Period
Test ThisTest This
Poison container = new AntPoison();Poison container = new AntPoison();
Insect bugType = new Ant();Insect bugType = new Ant();
public class Poison{ public void spray(Insect aBug){ System.out.println(“Generic Spray”); } public void spray(Ant antBug){ System.out.println(“Generic Ant Spray”); }};
public class AntPoison extends Poison{ public void spray(Ant antBug){ System.out.println(“Spraying Ant with Ant spray”); }};
Why?Why?
Because there is no Because there is no sprayspray method in method in AntAnt with an insect parameterwith an insect parameter
But, callingBut, callingPoison container = new AntPoison();Poison container = new AntPoison();
Spraying ant with ant spraySpraying ant with ant spray
Generic sprayGeneric spray Which at least works on ants.Which at least works on ants. Doesn’t work properly on insectsDoesn’t work properly on insects
Use Polymorphism ProperlyUse Polymorphism Properly
Can’t use 2 different container references Can’t use 2 different container references and 2 different parameter references at one and 2 different parameter references at one timetime
Do it in two stepsDo it in two steps Bounce from the Bounce from the PoisonPoison class to the Insect class to the Insect
class using class using beingSprayed() beingSprayed() methods in all methods in all classesclasses
Make use of Make use of thisthis, because it is , because it is staticallystatically determineddetermined
Fix up InsectFix up Insect
public class Poison{public class Poison{
public void spray (Insect aBug){public void spray (Insect aBug){
public class AntPoison{…} //no public class AntPoison{…} //no
//being Sprayed//being Sprayed
Put in the Bounce CallPut in the Bounce Call
public class Insect{public class Insect{ public void beingSprayed(Poisonpublic void beingSprayed(Poison aPoison){aPoison){ System.out.println(“Insect sprayedSystem.out.println(“Insect sprayed with poison”);}with poison”);}Public class Ant extends Insect{Public class Ant extends Insect{ public void beingSprayed(Poisonpublic void beingSprayed(Poison aPoison){aPoison){ System.out.println(“Ant sprayedSystem.out.println(“Ant sprayed with poison”);with poison”);}}}}
NoteNote
Because we used Because we used thisthis, the actual , the actual parameter of parameter of beingSprayedbeingSprayed is always of is always of type type PoisonPoison
Insect Insect is now working correctlyis now working correctly
TestTest
Poison container = new AntPoison();Poison container = new AntPoison();Insect aBug = new Ant();Insect aBug = new Ant();container.spray(aBug);container.spray(aBug);aBug = new Insect();aBug = new Insect();container.spray(aBug);container.spray(aBug);
ProducesProducesGeneric SprayGeneric SprayAnt being sprayed with poisonAnt being sprayed with poisonGeneric SprayGeneric SprayInsect being sprayed with poisonInsect being sprayed with poison
ProblemProblem
• We are only spraying with generic poisonWe are only spraying with generic poison• In order to make use of a In order to make use of a spray spray method in method in
the AntPoison class we must repeat the the AntPoison class we must repeat the spray() spray() method with exactly the same method with exactly the same signature in the signature in the AntPoisonAntPoison derived class derived class
• Furthermore, we need a Furthermore, we need a beingSprayed() beingSprayed() method of each poison type in both method of each poison type in both InsectInsect and and AntAnt
public class Poison{ public void spray(Insect aBug){ aBug.beingSprayed(this); }} ;
public class AntPoison extends Poison{ public void spray(Insect aBug){ aBug.beingSprayed(this); }};
public class Insect{ public void beingSprayed(Poison aPoison){ System.out.println(“Insect sprayed with generic poison”); } public void beingSprayed(AntPoison aPoison){ System.out.println(“Insect sprayed with ant poison”); }};
Public class Ant extends Insect{ public void beingSprayed(Poison aPoison){ System.out.println(“Ant sprayed with generic poison”); } public void beingSprayed(AntPoison aPoison){ System.out.println(“Ant sprayed with ant poison”); }};
RemarksRemarks
To insure polymorphism after the bounce To insure polymorphism after the bounce Insect Insect and and AntAnt must have 2 must have 2 beingSprayed()beingSprayed() methods with methods with differentdifferent signatures (i.e. parameters)signatures (i.e. parameters)
To have the ability to use ant poison the To have the ability to use ant poison the spray() spray() method is repeated method is repeated with the with the same signaturesame signature in both Insect and in both Insect and AntAnt
Let’s Test ThisLet’s Test This
Poison container = new AntPoison();Poison container = new AntPoison();
Insect aBug = new Ant();Insect aBug = new Ant();
container.spray(aBug);container.spray(aBug);
aBug = new Insect();aBug = new Insect();
container.spray(aBug);container.spray(aBug);
Poison container = new Poison();Poison container = new Poison();
Insect aBug = new Ant();Insect aBug = new Ant();
container.spray(aBug);container.spray(aBug);
aBug = new Insect();aBug = new Insect();
container.spray(aBug);container.spray(aBug);
Hooray!Hooray!
Ant sprayed with ant poisonAnt sprayed with ant poison
Insect sprayed with ant poisonInsect sprayed with ant poison
Ant sprayed with generic poisonAnt sprayed with generic poison
Insect sprayed with generic poisonInsect sprayed with generic poison
What we HaveWhat we Have
Poison
Spray(Insect)
AntPoison
Spray(Insect)
Insect
Ant
beingSprayed(Poison)
beingSprayed(Poison)
beingSprayed(AntPoison)
beingSprayed(AntPoison)
•Methods in Poison and AntPoison are identical!!
•Note output in Insect classes--Insect shouldn’t know anything about Poison
One Way OutOne Way Out
• Let the Let the beingSprayedbeingSprayed methods call other methods call other methods inthe Poison classesmethods inthe Poison classes• Call them Call them sprayIt()sprayIt()• Param types are with Param types are with InsectInsect and and AntAnt
• Put the print statements into the Put the print statements into the PoisonPoison (Visitor) classes(Visitor) classes
We ObtainWe ObtainInsect
Ant
Poison
AntPoison
beingSprayed(Poison)
beingSprayed(Poison)
Spray(Insect)
SprayIt(Insect)
SprayIt(Insect)SprayIt(Ant)
SprayIt(Ant)
print statements
Object Structure Visitor
Now SimplifyNow Simplify
• The above is the general solution to double The above is the general solution to double dispatchdispatch
• It is too general for our purposesIt is too general for our purposes• Make Make InsectInsect and and PoisonPoison abstract abstract• Begin with the Object Structure and eliminate Begin with the Object Structure and eliminate Spray()Spray() from from PoisonPoison
• SprayIt(Insect)SprayIt(Insect) is never called, so is never called, so eliminateeliminate
• We obtainWe obtain
beingSprayed(Poison)
beingSprayed(Poison)
Insect
Ant
Poison
Ant
SprayIt(Ant)
SprayIt(Ant)
Visitor Object Structure Poison.sprayIt(this)
Now Add the RoachesNow Add the Roaches
• Call Call beingSprayed() sprayAnt(),beingSprayed() sprayAnt(), because Insect is abstractbecause Insect is abstract
• You will need 2 methods, You will need 2 methods, sprayAnt(Ant)sprayAnt(Ant) as well as as well as sprayRoach(Roach)sprayRoach(Roach) in in PoisonPoison
• Note the excess baggage, e.g. spraying a Note the excess baggage, e.g. spraying a roach with ant poisonroach with ant poison
The Visitor PatternThe Visitor Pattern
Is a GoF PatternIs a GoF Pattern Purpose:Purpose: To implement operations on the To implement operations on the
objects of a structure without keeping those objects of a structure without keeping those operations in the object themselvesoperations in the object themselves
Key IdeaKey Idea: The operations that are executed : The operations that are executed depend on both the type of the operation and depend on both the type of the operation and the type of the node to which it is appliedthe type of the node to which it is applied
Advantage:Advantage: Extension is dead easy Extension is dead easy DisadvantageDisadvantage: Methods grow like weeds: Methods grow like weeds
In Our CaseIn Our Case
InsectInsect is the object structureis the object structure PoisonPoison is the visitor is the visitor Note the duplication in code—dangerous!Note the duplication in code—dangerous! The The InsectInsect classes have to know about classes have to know about
the the PoisonPoison classes classes There is a better way!There is a better way!
Do a double bounceDo a double bounce
Structure of the VisitorStructure of the Visitor
Poison sprayAnt(Ant);sprayRoach(Roach);
AntPoisonsprayAnt(Ant);sprayRoach(Roach);
RoachPoisonsprayAnt(Ant);sprayRoach(Roach);
The Visitor PatternThe Visitor Pattern
• Main idea: use an Main idea: use an iteratoriterator or or traversaltraversal to visit to visit each node of the object structure and visit it with each node of the object structure and visit it with the corresponding node of the visitor structurethe corresponding node of the visitor structure
• The object structure classes have no knowledge of The object structure classes have no knowledge of the visitor classesthe visitor classes
• What gets carried out depends on two thingsWhat gets carried out depends on two things• The type of the visitorThe type of the visitor• The type of the object nodeThe type of the object node
• Hence double dispatchHence double dispatch
Object Structure VisitedObject Structure Visited
InsectgetSprayed(Poison);
AntgetSprayed(Poison p)
RoachgetSprayed(Poison p)
p.sprayAnt(this); p.sprayRoach(this);
Structure of the Visitor PatternStructure of the Visitor Pattern