Last active
January 8, 2017 21:06
-
-
Save nuttycom/6e286855bc67b3d89096824eba33d531 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ShapeVisitor<A> | |
{ | |
// The implementation of ApplyRect defines handling for the | |
// operation defined by this visitor in the case that the | |
// shape is a rectangle. | |
public A ApplyRect(IRectangle rect); | |
// The implementation of ApplyCircle defines handling for the | |
// operation defined by this visitor in the case that the | |
// shape is a circle. | |
public A ApplyCircle(ICircle circle); | |
} | |
public class AreaVisitor : ShapeVisitor<double> | |
{ | |
public double ApplyRect(IRectangle rect) | |
{ | |
return rect.height * rect.width; | |
} | |
public double ApplyCircle(ICircle circle) | |
{ | |
return Math.PI * circle.radius * circle.radius ; | |
} | |
} | |
public class PerimeterVisitor: ShapeVisitor<double> | |
{ | |
public double ApplyRect(IRectangle rect) | |
{ | |
return 2 * (rect.height + rect.width); | |
} | |
public double ApplyCircle(ICircle circle) | |
{ | |
return Math.PI * circle.radius * 2; | |
} | |
} | |
abstract class IShape { | |
public A accept<A>(ShapeVisitor<A> visitor); | |
// This becomes essentially syntactic sugar; it need not be defined as a method on the interface. | |
public double GetArea() | |
{ | |
return accept(new AreaVisitor()); | |
} | |
// I will not define GetPerimeter here - there is no purpose. The user | |
// can simply call myShape.accept(new PerimeterVisitor()) if they | |
// wish that functionality. The point here is that the end user can "extend" | |
// the interface by adding new Visitor implementations - they do not need | |
// IShape to be altered. | |
} | |
class ICircle : IShape { | |
public A accept<A>(ShapeVisitor<A> visitor) { | |
return visitor.ApplyCircle(this); | |
} | |
} | |
class IRectangle: IShape { | |
public A accept<A>(ShapeVisitor<A> visitor) { | |
return visitor.ApplyRect(this); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Real word apps are full of types like double, string, etc and they're useful when you have to deliver an app within a deadline and you don't have time to add tons of code without any additional feature from the user perspective. Anyway, there is another point and it is related to the state handling. Let me explain it below.
Oh ... and this is a big problem: with a switch statement I can manage a mutable state IShape that is now Rectangle and then Circle. I don't see how it could be done with a Visitor, since I should accept a generic IShape and that's against the Visitor pattern in the first place. Have a look at my latest repository and tell me if you see any way - using C# as a language - to replace this switch with a Visitor?
Thank you again!