Skip to main content
added 307 characters in body
Source Link
Doc Brown
  • 220.3k
  • 35
  • 410
  • 623

What you described meansHere is a straightforward solution, expressing the case literally to: implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2:

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here, which would require
// to provide accept(Visitor v) 
public ElementB { 
    public void accept(Visitor2 v) {
        //...
    }
}

This avoids the issue of two very similar ElementA.accept methods, which leads to the extendability problem mentioned in your question.

However, this solution will not work if the intention is to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB (both derived from Visitable), and also not knowing if someVisitor is of type Visitor1 or Visitor2 (both derived from Visitor) . If that's the case, there is no way to prevent getting a combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • maybe you want the behaviour from solution 1, where the forbidden combination throws an exception (so the caller can react accordingly)

  • maybe you want nothing to happen - similar to solution 1, but with Vistor1.visit(ElementB element) implemented empty (so the caller does not have to care for)

  • or maybe you prefer todon't need any generic caller. Then you can give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitors of type Visitor2 (using my suggestion from above).

So look at the requirements of the caller - ask yourself: how will you are going to use the visitors (why do you need them at all), and which degree of genericity are you trying to achieve?

What you described means literally to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2:

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

This avoids the issue of two very similar ElementA.accept methods, which leads to the extendability problem mentioned in your question.

However, this solution will not work if the intention is to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB (both derived from Visitable), and also not knowing if someVisitor is of type Visitor1 or Visitor2 (both derived from Visitor) . If that's the case, there is no way to prevent getting a combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • maybe you want the behaviour from solution 1, where the forbidden combination throws an exception

  • maybe you want nothing to happen - similar to solution 1, but with Vistor1.visit(ElementB element) implemented empty

  • or maybe you prefer to give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitors of type Visitor2 (using my suggestion from above).

Here is a straightforward solution, expressing the case literally: implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2:

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

// no derivation from Visitable here, which would require
// to provide accept(Visitor v) 
public ElementB { 
    public void accept(Visitor2 v) {
        //...
    }
}

This avoids the issue of two very similar ElementA.accept methods, which leads to the extendability problem mentioned in your question.

However, this solution will not work if the intention is to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB (both derived from Visitable), and also not knowing if someVisitor is of type Visitor1 or Visitor2 (both derived from Visitor) . If that's the case, there is no way to prevent getting a combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • maybe you want the behaviour from solution 1, where the forbidden combination throws an exception (so the caller can react accordingly)

  • maybe you want nothing to happen - similar to solution 1, but with Vistor1.visit(ElementB element) implemented empty (so the caller does not have to care for)

  • or maybe you don't need any generic caller. Then you can give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitors of type Visitor2 (using my suggestion from above).

So look at the requirements of the caller - ask yourself: how will you are going to use the visitors (why do you need them at all), and which degree of genericity are you trying to achieve?

added 136 characters in body
Source Link
Doc Brown
  • 220.3k
  • 35
  • 410
  • 623

I would suggestWhat you described means literally to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2.:

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

That way, you avoidThis avoids the code duplicationissue of two very similar ElementA.accept methods, which leads to the extendability problem mentioned in your question.

I guessHowever, this solution will not work if the real problemintention is here that you intent to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB (both derived from Visitable), and also not knowing if someVisitor is of type Visitor1 or Visitor2, hence you still want ElementB to be(both derived from VisitableVisitor) . If that's the case, you cannot there is no way to prevent thegetting a combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • use solution 1, throw an exception, if the calling code can handle such exceptions

    maybe you want the behaviour from solution 1, where the forbidden combination throws an exception

  • do nothing - which means your solution 1, but implement Vistor1.visit(ElementB element) empty

    maybe you want nothing to happen - similar to solution 1, but with Vistor1.visit(ElementB element) implemented empty

  • or give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitory of type Visitor2 (using my suggestion from above).

    or maybe you prefer to give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitors of type Visitor2 (using my suggestion from above).

I would suggest to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2.

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

That way, you avoid the code duplication which leads to the extendability problem mentioned in your question.

I guess the real problem is here that you intent to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB, and also not knowing if someVisitor is Visitor1 or Visitor2, hence you still want ElementB to be derived from Visitable. If that's the case, you cannot prevent the combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • use solution 1, throw an exception, if the calling code can handle such exceptions
  • do nothing - which means your solution 1, but implement Vistor1.visit(ElementB element) empty
  • or give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitory of type Visitor2 (using my suggestion from above).

What you described means literally to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2:

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

This avoids the issue of two very similar ElementA.accept methods, which leads to the extendability problem mentioned in your question.

However, this solution will not work if the intention is to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB (both derived from Visitable), and also not knowing if someVisitor is of type Visitor1 or Visitor2 (both derived from Visitor) . If that's the case, there is no way to prevent getting a combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • maybe you want the behaviour from solution 1, where the forbidden combination throws an exception

  • maybe you want nothing to happen - similar to solution 1, but with Vistor1.visit(ElementB element) implemented empty

  • or maybe you prefer to give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitors of type Visitor2 (using my suggestion from above).

added 58 characters in body
Source Link
Doc Brown
  • 220.3k
  • 35
  • 410
  • 623

I would suggest to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2.

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

That way, you avoid the code duplication which leads to the extendability problem mentioned in your question.

I guess the real problem is here that you intent to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB, and also not knowing if someVisitor is Visitor1 or Visitor2, hence you still want ElementB to be derived from Visitable. If that's the case, you cannot prevent the combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • use solution 1, throw an exception, if the calling code can handle such exceptions
  • do nothing - which means your solution 1, but implement Vistor1.visit(ElementB element) empty
  • or give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitory of type Visitor2 (using my suggestion from above).

I would suggest to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2.

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

That way, you avoid the code duplication which leads to the extendability problem mentioned in your question.

I would suggest to implement ElementA.accept in terms of the base class Visitor, and ElementB.accept in terms of Visitor2.

public ElementA implements Visitable {
    public void accept(Visitor v) {
        //...
    }
}

public ElementB { // no derivation from Visitable here
    public void accept(Visitor2 v) {
        //...
    }
}

That way, you avoid the code duplication which leads to the extendability problem mentioned in your question.

I guess the real problem is here that you intent to have some generic code which calls visitable.accept(someVisitor) without knowing beforehand if visitable is of type ElementA or ElementB, and also not knowing if someVisitor is Visitor1 or Visitor2, hence you still want ElementB to be derived from Visitable. If that's the case, you cannot prevent the combination of objects Visitor1 with ElementB at runtime without loosing the genericity. Hence you need to decide how you want the calling code to behave in case someone passes the forbidden combination in there:

  • use solution 1, throw an exception, if the calling code can handle such exceptions
  • do nothing - which means your solution 1, but implement Vistor1.visit(ElementB element) empty
  • or give up the genericity, make one function which calls ElementA.accept with arbitrary visitors, and a second one which calls ElementB.accept only with visitory of type Visitor2 (using my suggestion from above).
added 58 characters in body
Source Link
Doc Brown
  • 220.3k
  • 35
  • 410
  • 623
Loading
Source Link
Doc Brown
  • 220.3k
  • 35
  • 410
  • 623
Loading