The one that the authors of Design Patterns themselves most worried about was the "Visitor" pattern.
It's a "necessary evil" - but is often over used and the need for it often reveals a more fundamental flaw in your design.
An alternative name for the "Visitor" pattern is "Multi-dispatch", because the Visitor pattern is what you end up with when you wish to use a single-type dispatch OO language to select the code to use based on the type of two (or more) different objects.
The classic example being that you have the intersection between two shapes, but there's an even simpler case that's often overlooked: comparing the equality of two heterogeneous objects.
Anyway, often you end up with something like this:
interface IShape
{
double intersectWith(Triangle t);
double intersectWith(Rectangle r);
double intersectWith(Circle c);
}
The problem with this is that you have coupled together all of your implementations of "IShape". You've implied that whenever you wish to add a new shape to the hierarchy you will need to change all the other "Shape" implementations too.
Sometimes, this is the correct minimal design - but think it through. Does your design really mandate that you need to dispatch on two types? Are you willing to write each of the combinatorial explosion of multi-methods?
Often, by introducing another concept you can reduce the number of combinations that you're actually going to have to write:
interface IShape
{
Area getArea();
}
class Area
{
public double intersectWith(Area otherArea);
...
}
Of course, it depends - sometimes you really do need to write code to handle all of those different cases - but it's worth taking pause and having a think before taking the plunge and using Visitor. It might save you a lot of pain later on.