My Impressions and Suggestions about Software Development in the 21th Century. Or something like that.
June 23, 2009
Problems starting apps on the iPhone 3GS
June 21, 2009
Playing around with Java Scenegraph and Swing
June 18, 2009
Visiting the Family - An Advanced Application of the Visitor Pattern
This is the second post in a loosely scheduled series of articles about the Visitor Pattern. Please find the first one here.
One of those things we've learned last time is the simple fact, that the Visitor will only visit "leafs" in a complex class hierarchy. Otherwise the polymorphic type dispatching will not work. Well, but we are sometimes faced with situations, where this limitation is not acceptable. Let's look at some fancy example, to illustrate my explanations. And since we all spent our two years military service with the imperial guards, here's an obvious taxonomy of different star wars vehicle types. Usually complex type systems consist of several levels of abstraction, like our example. Here we have three:
- Either everything is the same, namely a Vehicle
- or it is a Vehicle Class like StarShip or Walker,
- or it is a concrete Vehicle like, well ... the BWing, for instance.
// StarShips... public abstract class StarShip extends Vehicle{ public void fly(){ System.out.println("Yeaahhh, I'm flying, Baby."); } } // Walker public abstract class Walker extends Vehicle{ public void walk(){ System.out.println("I'm going for a walk."); } }As a fleet commander we know for sure that we can utilize the Visitor Pattern to command our
Vehicle [] fleet = { new BWing(), new XWing(), new AtAt() }
.
A fleet lieutenant would do it like this:
// clumsy fleet lieutenant's way to command his units public class ClumsyVisitor implements Visitor{ public void visit(BWing bwing) { bwing.fly(); } public void visit(XWing xwing) { xwing.fly(); } public void visit(AtAt atat) { atat.walk(); } }But we would not have become commander if we would unnecessarily repeat ourselves. As you've already realized, this is code duplication since we don't operate on the correct level of abstraction. The proper way is calling methods on the Vehicle Classes, not on the concrete Vehicles. But again, how to we do that? Here's the solution:
public abstract class AbstractVehicleClassVisitor implements Visitor { public abstract void visit(Walker walker); public abstract void visit(StarShip starShip); public void visit(BWing bwing) { visit((StarShip) bwing); } public void visit(XWing xwing) { visit((StarShip) xwing); } public void visit(AtAt atat) { visit((Walker) atat); } }Tata: We've just introduced the proper level of abstraction to our Visitor as well by deriving a new type from Visitor, the AbstractVehicleClassVisitor. Or to be more precise, we defined the missing
visit(Walker)
and visit(StarShip)
methods and delegate the 'leaf visits' to these new abstract methods. Visiting Vehicle Classes is now done by extending the AbstractVehicleVisitor. Hence our fleet commander command simply looks like:
// that's how we command! public class MoveVisitor extends AbstractVehicleClassVisitor{ public void visit(Walker walker) { walker.walk(); } public void visit(StarShip starShip) { starShip.fly(); } }Calling for the troops breaks down to
Vehicle [] fleet = { new BWing(), new XWing(), new AtAt() }; for(Vehicle unit : fleet) { unit.accept(new MoveVisitor()); } /* Which would output Yeaahhh, I'm flying, Baby. Yeaahhh, I'm flying, Baby. I'm going for a walk. */Yep, that's all. Easy, isn't?
June 16, 2009
My Two Cents about Coding in English
After working for three years in an international project I absolutely agree with his opinion. Having no other chance to communicate with my japanese and indian colleagues than in english, the first few weeks were really hard. But I've learned several things:
- It does not matter whether you speak 100% grammatically correct. It's more important to talk fluent and confident rather than being sure, that every grammar rule you've learned 10 years ago is correctly applied. My impression is people respect me because of my technical reputation, not because I do speak absolutely error free. (I doubt that I do, this blog gives many proofs)
- The more you do things, the better you get. And the more confident you get. As Jens said, it's right, start reading things english, write things in english, and if you have the chance, do speak as much english as you can.
But meanwhile I've also seen the other side of the medal: If your code is commented in your mother tongue - or even more worse: Implemented in your mother tongue - then you've got a more or less limited market of people how can replace you. If the code is in english you extend the potential candidates to the rest of the industrialized world. And if you now consider that people in east europe, asia and india cost about a fourth of your salary, then you might start worrying. Currently I do not worry about these aspects, but if you were stuck in your job for 20 years, have not learned contemporary technologies then you might not be attractive for a modern, agile market and maybe you have a different opinion about this topic. But on the other hand, if you are one these people, you might not read blogs as well :-)
June 11, 2009
Hail to the Visitor Pattern
Let's fetch up those of you, who are not familiar with the Visitor at all. This pattern enables injecting methods into types. 'Why the hell, do I want to do this?' you might ask. Well, consider you have some micky mouse type hierarchy of geometry related classes:
And you want to add functionality to these classes, like drawing. You could
add a purely virtual method draw()
to the super class and provide
an implementation in all of the sub classes, since all of our subclasses are
drawn differently, of course. Yes, indeed you could do this. But what if such
a method would introduce dependencies you damn want to avoid with your plain
classes? To stay in our example, let's assume we want draw our Geometries with
QT. Hence we would implement QT depending code in draw()
. This
would make our classes dependent of QT. But what if we don't want this?
Because we also want to allow drawing it in AWT? what now? Add
drawMeWithAWT()
as well? And then add new dependencies? I don't
know about you, but surely I don't want this! Therefore, what else can we do.
Ah, I've got an idea. There must have been a reason, why god (or at least
James Gosling) has invented instanceof
in Java:
public void drawGeometry(Geometry g){ if(g instanceof Polygon){ drawPolygon((Polygon) g); }else if(g instanceof Circle){ drawCircle((Circle) g); }else if(g instanceof Line){ drawLine((Line) g); }else { throw new RuntimeException("Unknown type"); } }Ok, let's look at the code closely. Does your brain hurt and do your eyes bleed already? No? Look again! They should! Please say loud to yourself: 'This is bad code!'. Why? Because it's the prototype example of violating the Open Closed Principle: You have some generalization (here Geometry) and make assumptions about existing sub types. The overall idea of generalization is well, generalize the fact that there are sub types. But why is it so awful evil? Because it is not maintainable. What happens if you start adding new sub types to Geometry? You would have to extend every single dispatching block and add a new else if for your new type. And code which relies on this idiom does not stop with a single block of such if else nonsense. No. It will spread through the whole code. And I would bet a serious amount of money (if I would have a serious amount of money) that you miss at least one place where you have to add your new sub type.
The rescue to this problem is polymorphism. But we've already been at this point. So we don't want polymorphism in the type hierarchy itself like our draw() method. But what now? Well, please step aside for the Visitor pattern. It lets you write specialized handling for each type, but prevents you from implementing the type dispatching on your own. How? Have a look:
The trick is SubElement's implementation of accept:
public void accept(Visitor visitor){ visitor.visit(this); }This is the magic polymorphic dispatching code! Let's see it in action:
Element elem = new SubElement(); elem.accept(new ConcreteVisitor());Ok, not much action. But all we need for the explanation. We treat our SubElement as a general Element. Calling the polymorphic accept actually on SubElement will take care that the visit(SubElement) is finally executed. Hence we did our dispatching, but without any if or even else. That's the power of polymorphism!
Now let's go back to our Geometry world and see a more complex example:
Here we have our DrawVisitor, who is responsible for drawing. The class hierarchy just depends on Visitor and therefore knows nothing about our concrete DrawVisitor. This goal has been reached. But, wait, we get even more, for free. People usually advice you to use the Visitor on a stable class hierarchy, hence on such, which does not frequently add new classes. Of course, this is correct. Let's assume our classes would belong to a framework and therefore we would not know anything about the client. if we constantly add new classes to the model and change the interface people could become quite angry with us.
But (and that's a very huge but in my opinion) if you change your model, add new classes and add the respective visit(NewClass) methods to the Visitor then you get a compile time check whether you have taken care of handling the new classes in all of your visitor's implementations. And having problems reported by the compiler is one of the major advantages of a static type system, in my honest opinion.
You might have noticed that Visitor visits all concrete classes, but not the abstract super class. This is the necessary otherwise the whole dispatching mechanism does not work. But on the other hand this introduces some challenges on more complex type systems, where we have several levels of abstraction. Even here we can use the visitor and build some handy tools with it to savely navigate such hierarchies, but I think this might be an issue for another post.
Summarizing what we've learned today: The Visitor pattern enables us to dispatch type hierarchies without violating the Open Closed principle by injecting methods in classes and relying on good old runtime polymorphism.
Or do you have a complete different opinion on this topic?