ЛОР, а как ты предпочитаешь реализовывать подобного рода конструкции?
Казалось бы doSpecificComplexTask() нужно сделать методом Link и переопределить его в каждом наследнике, но что если в этом методе может быть довольно нетривиальной код, который хочется держать отдельно от данных (например, работа с сетью, базой, etc...). Т.е. хочется, чтобы класс Link был скорее структурой?
Visitor - очень громоздко, instanceof - в Java говорят плохой стиль. Хотя если разобраться, то чем Pattern Matching из Scala не instanceof?
Да, это ООП головного мозга.
Java:
public interface Entity {
    String getId();
    String getMessaage();
    Link getLink();
}
public interface Link {
    
    void accept(Visitor visitor);
    static interface Visitor {
        visit(UrlLink link);
        visit(SomethingElseLink link);
        visit(EvenMoreLink link);
    }    
    static abstract class UrlLink() implements Link {
        void accept(Visitor visitor) { visitor.accept(this); }
        URL getURL();
    }
    static abstract class SomethingElseLink() implements Link {
        void accept(Visitor visitor) { visitor.accept(this); }
        SomethingElse getSomethingElse();
        AndSomethingElse getAndSomethingElse();
    }
    static abstract class EvenMoreLink() implements Link {
        void accept(Visitor visitor) { visitor.accept(this); }
        EvenMore getEvenMore();
    }
}
// Variant 1
class SpecificVisitor implements Link.Visitor { ... }
SpecificVisitor visitor = new SpecificVisitor();
entity.getLink().accept(visitor);
// Variant 2
Link link = entity.getLink();
if (link instanceof UrlLink) { doSpecificComplexTask(...); }
if (link instanceof SomethingElseLink) { doSpecificComplexTask(...); }
if (link instanceof EvenMoreLink) { doSpecificComplexTask(...); }
Scala:
class Entity(id: String, message: String, link: Link)
trait Link
case class UrlLink(url: URL)
case class SomethingElseLink(se: SomethingElse, ase: AndSomethingElse)
case class EvenMoreLink(em: EvenMore)
entity match {
    case UrlLink(url) => doSpecificComplexTask(url)
    case SomethingElseLink(se, ase) => doSpecificComplexTask(se, ase)
    case EvenMoreLink(em) => doSpecificComplexTask(em)
}





