vendredi 27 octobre 2017

Is it acceptable to return a canonical representation subclass from an abstract base class?

Suppose you have the following:

  • an abstract base class that implements common functionality;
  • a concrete derived class that serves as the canonical representation.

Now suppose you want any inheritor of the base class to be convertible to the canonical representation. One way of doing this is by having an abstract method in the base class that is meant to return a conversion of the inheritor as an instance of the canonical derived class.

However, it seems to be generally accepted that base classes should not know about any of their derived classes, and in the general case, I agree. However, in this scenario, this seems to be the best solution because it enables any number of derived classes, each with their own implementation we don't need to know anything about, to be interoperable via the conversion to the canonical representation that every derived class has to implement.

Would you do it differently? Why and how?

An example for geometric points:

// an abstract point has no coordinate system information, so the values
// of X and Y are meaningless
public abstract class AbstractPoint {
    public int X;
    public int Y;

    public abstract ScreenPoint ToScreenPoint();
}

// a point in the predefined screen coordinate system; the meaning of X 
// and Y is known
public class ScreenPoint : AbstractPoint {
    public ScreenPoint(int x, int y) {
        X = x;
        Y = y;
    }

    public override ScreenPoint ToScreenPoint()
        => new ScreenPoint(X, Y);
}

// there can be any number of classes like this; we don't know anything
// about their coordinate systems and we don't care as long as we can
// convert them to `ScreenPoint`s
public class ArbitraryPoint : AbstractPoint {
    private int arbitraryTransformation;

    public ArbitraryPoint(int x, int y) {
        X = x;
        Y = y;
    }

    public override ScreenPoint ToScreenPoint()
        => new ScreenPoint(X * arbitraryTransformation, Y * arbitraryTransformation);

    // (other code)
}

Aucun commentaire:

Enregistrer un commentaire