jeudi 13 octobre 2016

After Factory object creation: How to call a method only defined in some cases?

I have a class (let's call it MyClass for now) that can have different characteristics: It must be either A1 or A2 (but not both) and it must be B1 or B2 (but not both). With those characteristics come different fields and different functionality. I decided to model this by implementing A1 to B2 as traits and mix them into the instantiation as needed. Determining which kind of object I want during instantiation is tricky, so I opted for a Factory Pattern, specifically a companion object to MyClass (constructor of MyClass is private). But if I use MyClass as the return type of the factory method as in

def create(...parameters...): MyClass {
    if(...parameters' complex calculations...) {
        new MyClass(...) with A1
    } else {
        new MyClass(...) with A2
    }
 }

I am not able to use the methods in A1 or A2 when I instanciate with

 val a = MyClass.create(...parameters...)
 a.methodFromA1 // not available

This is not surprising, because the type of a is MyClass and not MyClass with A1. ...parameters... are determined at runtime, not compile time, and thus the available methods would be determined at runtime, which is not possible for a type-safe language.

How should I solve this?

One idea of mine is to have somehow work with sealed traits and turn the traits A1, A2, B1, B2 into case classes. After all I would probably need to use some sort of pattern matching later anyway. In my case with just four possible combinations (MyClass with A1 with B1, MyClass with A1 with B2, MyClass with A2 with B1, MyClass with A2 with B2) this might even feasible, but if I just had one more pair of traits, this would get pretty ugly pretty fast. I have not been able to figure out the details.

I hope there is some kind of design pattern for this - I should not be the first to have this issue. In http://ift.tt/2dOSF7w an example is given that an Animal factory can return a Dog or a Cat, depending on a String input. If you imagine that a Dog has a bark method that we want to use as a client after creation, but a Cat does not - that situation should be very similar to mine.

Aucun commentaire:

Enregistrer un commentaire