3

Assume:

  1. There is some module whose interface is IA.
  2. There is some module B, that takes in a parameter an instance of IA, and whose behavior depends upon the type of that IA,

meaning (pseudo code, no specific language)

class B{
    IA ia;
    B(IA ia){
        this.ia = ia;
    }
    doStuff(){
        if(type(this.ia)==A1){
             print("A1");
        }
        if(type(this.ia)==A2){
             print("A2");
        }
    }
}

I realize I could add some public method foo to ia, and thus the code would simplify to

class B{
    IA ia;
    B(IA ia){
        this.ia = ia;
    }
    doStuff(){
        this.ia.foo();
    }
}

My question is twofold:

  1. What is the correct design to achieve this if I (for some reason) can't change IA, meaning, I can't add foo()?

  2. What is the correct (scalable) design if I am allowed to change IA but the same problem now repeats for A1, A2, and so on, meaning

the final desired behavior is

class B{
    IA ia;
    B(IA ia){
        this.ia = ia;
    }
    doStuff(){
        if(type(this.ia)==A1){
             if(type(this.ia.iz)==Z1){
                 print("A1Z1");
                 print("unique treatment");
             }
             if(type(this.ia.iz)==Z2){
                 print("A1Z2");
                 print("special treatment");
             }
        }
        if(type(this.ia)==A2){
             if(type(this.ia.iz)==Z1){
                 print("Z1A2");
                 print("one of a kind treatment");
             }
             if(type(this.ia.iz)==Z2){
                 print("Z2A2");
                 print("Wow treatment");
             }
        }
    }
}

and can repeat more times.

Please notice Z1 and Z1 are the same for A1 and A2!. And again, the same can go on, IZ can contain IX of several types, with unique behaviors

I wonder if case 2 is at all separate of modular, in the sense that, the behavior is unique for every type-combination, and no behavior can really be extracted to a more abstract level.

I still don't like the type checking, and wonder if there is something that can be done which looks better.

3
  • 1
    What you are looking for is called "double dispatch". Available design alternatives may depend on the programming language you are using, try to google "double dispatch [your favorite programming language]. – Doc Brown Feb 23 '19 at 23:24
  • 2
    From your description ("And again, the same can go on"), I get the sense that you actually need multiple dispatch (as in, more then double); but maybe there's an alternative approach. BTW, is this more of a hypothetical question or are you actually trying to work with a library that has a type hierarchy that doesn't quite fit what you need to do? You can probably arrange things so that you are not relying on that hierarchy and work with concrete types instead, but can you give us more info (more context)? – Filip Milovanović Feb 24 '19 at 0:55
  • This is really hard to answer when it's this abstract. Can you not provide a more concrete example? – Paul Feb 24 '19 at 16:36
1

One option here is to create a new interface with foo() and then wrapper types for that interface that contain the specific logic you want for each type. Then it's simply a matter of wrapping each IA instance.

Depending on how these IA instances are created, you may not be able to do this without checking the type at the point of wrapping. This therefore may not eliminate the need to do type checking but it will allow you to keep that bit of nastiness in confined to method that does nothing else. Then that allows your B class to work the way you desire.

A similar but different approach would be to create B classes that correspond to each IA type you want to deal with differently. Then, just like above, you need some code to check the type of the IA in order to get the appropriate B type but it's separate from the application logic.

0

Look up the visitor design pattern. It looks to me that it may apply to the problem you are trying to solve, whereby your IA would be the root of the complex data structure that you want to visit with a logic dependent upon its static and/or dynamic type shape, and which is seemingly subject to evolution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.