Download presentation
Presentation is loading. Please wait.
Published byAugustus Stanley Modified over 9 years ago
1
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) insects with generic spray If there is not a complete match between the signatures of methods in base and derived classes there is no polymorphism If there is not a complete match between the signatures of methods in base and derived classes there is no polymorphism Compiler determines the call by using the declared type Compiler determines the call by using the declared type Now apply this Now apply this
2
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”); } };
3
Remarks It appears that we are attempting to use polymorphism both on the Poison type and the Insect type It appears that we are attempting to use polymorphism both on the Poison type and the Insect type The only polymorphism that will work is with a static reference to Poison (and a run-time reference to either Poison or AntPoison ) and a static reference to Ant. Period The only polymorphism that will work is with a static reference to Poison (and a run-time reference to either Poison or AntPoison ) and a static reference to Ant. Period
4
Test This Poison container = new AntPoison(); Insect bugType = new Ant(); container.spray(bugType); bugType = new Insect(); container.spray(bugType);Produces Generic Spray
5
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”); } };
6
Why? Because there is no spray method in Ant with an insect parameter But, calling Poison container = new AntPoison(); Container.spray(new Ant()); Container.spray(new Insect());
7
Results Produces Produces Spraying ant with ant spray Generic spray Which at least works on ants. Doesn’t work properly on insects
8
Use Polymorphism Properly Can’t use 2 different container references and 2 different parameter references at one time Do it in two steps Bounce from the Poison class to the Insect class using beingSprayed() methods in all classes Make use of this, because it is statically determined
9
Fix up Insect public class Poison{ public void spray (Insect aBug){ public void spray (Insect aBug){ System.out.println(“Generic System.out.println(“Generic Spray”); Spray”); aBug.beingSprayed(this); } aBug.beingSprayed(this); }} public class AntPoison{…} //no //being Sprayed //being Sprayed
10
Put in the Bounce Call public class Insect{ public void beingSprayed(Poison public void beingSprayed(Poison aPoison){ aPoison){ System.out.println(“Insect sprayed System.out.println(“Insect sprayed with poison”);} with poison”);} Public class Ant extends Insect{ public void beingSprayed(Poison public void beingSprayed(Poison aPoison){ aPoison){ System.out.println(“Ant sprayed System.out.println(“Ant sprayed with poison”); with poison”);}}
11
Note Because we used this, the actual parameter of beingSprayed is always of type Poison Insect is now working correctly
12
Test Poison container = new AntPoison(); Insect aBug = new Ant(); container.spray(aBug); aBug = new Insect(); container.spray(aBug);Produces Generic Spray Ant being sprayed with poison Generic Spray Insect being sprayed with poison
13
Problem We are only spraying with generic poison We are only spraying with generic poison In order to make use of a spray method in the AntPoison class we must repeat the spray() method with exactly the same signature in the AntPoison derived class In order to make use of a spray method in the AntPoison class we must repeat the spray() method with exactly the same signature in the AntPoison derived class Furthermore, we need a beingSprayed() method of each poison type in both Insect and Ant Furthermore, we need a beingSprayed() method of each poison type in both Insect and Ant
14
public class Poison{ public void spray(Insect aBug){ aBug.beingSprayed(this); } } ; public class AntPoison extends Poison{ public void spray(Insect aBug){ aBug.beingSprayed(this); } };
15
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 ” ); } };
16
Remarks To insure polymorphism after the bounce Insect and Ant must have 2 beingSprayed() methods with different signatures (i.e. parameters) To have the ability to use ant poison the spray() method is repeated with the same signature in both Insect and Ant
17
Let’s Test This Poison container = new AntPoison(); Insect aBug = new Ant(); container.spray(aBug); aBug = new Insect(); container.spray(aBug); Poison container = new Poison(); Insect aBug = new Ant(); container.spray(aBug); aBug = new Insect(); container.spray(aBug);
18
Hooray! Ant sprayed with ant poison Insect sprayed with ant poison Ant sprayed with generic poison Insect sprayed with generic poison
19
What we Have Poison Spray(Insect) AntPoison Spray(Insect) Insect Ant beingSprayed(Poison) beingSprayed(AntPoison) Methods in Poison and AntPoison are identical!! Note output in Insect classes-- Insect shouldn’t know anything about Poison
20
One Way Out Let the beingSprayed methods call other methods inthe Poison classes Let the beingSprayed methods call other methods inthe Poison classes Call them sprayIt() Call them sprayIt() Param types are with Insect and Ant Param types are with Insect and Ant Put the print statements into the Poison (Visitor) classes Put the print statements into the Poison (Visitor) classes
21
We Obtain Insect Ant Poison AntPoison beingSprayed(Poison) Spray(Insect) SprayIt(Insect) SprayIt(Ant) print statements Object Structure Visitor
22
Now Simplify The above is the general solution to double dispatch The above is the general solution to double dispatch It is too general for our purposes It is too general for our purposes Make Insect and Poison abstract Make Insect and Poison abstract Begin with the Object Structure and eliminate Spray() from Poison Begin with the Object Structure and eliminate Spray() from Poison SprayIt(Insect) is never called, so eliminate SprayIt(Insect) is never called, so eliminate We obtain We obtain
23
beingSprayed(Poison) Insect Ant Poison Ant SprayIt(Ant) VisitorObject StructurePoison.sprayIt(this)
24
Now Add the Roaches Call beingSprayed() sprayAnt(), because Insect is abstract Call beingSprayed() sprayAnt(), because Insect is abstract You will need 2 methods, sprayAnt(Ant) as well as sprayRoach(Roach) in Poison You will need 2 methods, sprayAnt(Ant) as well as sprayRoach(Roach) in Poison Note the excess baggage, e.g. spraying a roach with ant poison Note the excess baggage, e.g. spraying a roach with ant poison
25
The Visitor Pattern Is a GoF Pattern Purpose: To implement operations on the objects of a structure without keeping those operations in the object themselves Key Idea: The operations that are executed depend on both the type of the operation and the type of the node to which it is applied Advantage: Extension is dead easy Disadvantage: Methods grow like weeds
26
In Our Case Insect is the object structure Poison is the visitor Note the duplication in code—dangerous! The Insect classes have to know about the Poison classes There is a better way! Do a double bounce
27
Structure of the Visitor Poison sprayAnt(Ant); sprayRoach(Roach); AntPoison sprayAnt(Ant); sprayRoach(Roach); RoachPoison sprayAnt(Ant); sprayRoach(Roach);
28
The Visitor Pattern Main idea: use an iterator or traversal to visit each node of the object structure and visit it with the corresponding node of the visitor structure Main idea: use an iterator or traversal to visit each node of the object structure and visit it with the corresponding node of the visitor structure The object structure classes have no knowledge of the visitor classes The object structure classes have no knowledge of the visitor classes What gets carried out depends on two things What gets carried out depends on two things The type of the visitor The type of the visitor The type of the object node The type of the object node Hence double dispatch Hence double dispatch
29
Object Structure Visited Insect getSprayed(Poison); Ant getSprayed(Poison p) Roach getSprayed(Poison p) p.sprayAnt(this);p.sprayRoach(this);
30
Structure of the Visitor Pattern VisitConcreteElementA(ConcreteElementA) VisitConcreteElementB(ConcreteElementB) VisitConcreteElementA(ConcreteElementA) VisitConcreteElementB(ConcreteElementB) Visitor ConcreteVisitor1 VisitConcreteElementB(ConcreteElementB) VisitConcreteElementA(ConcreteElementA) ConcreteVisitor2 The Visitor
31
Object Structure Accept(Visitor) Element ConcreteElementA Accept(Visitor v) OperationA() ConcreteElementA Accept(Visitor v) OperationB() v->VisitConcreteElementB(this) v->VisitConcreteElementA(this) ObjectStructure
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.