mercredi 5 octobre 2022

Suggestion on Pattern to solve concrete class specialization

Suppose that you have several data objects that share some common fields and inherit from a base object.

class BaseProduct {
String productId;
String productType; // i.e. {A, B}.
}

class ConcreteProductA extends BaseProduct {
...
String concreteAttA;
}

class ConcreteProductB extends BaseProduct {
...
String concreteAttB;
}

Now suppose I can create packages containing a specific type of product, and that the implementation of the function that creates the package is different depending on the concrete type being packaged. However, Ideally, I'd want to encapsulate that specific behavior behind an abstraction, as I'd always want to take the same steps (i.e. preparePackage) for any type of product. In other words, I want to be calling packageManager.preparePackage from the following excerpt:

interface PackageBuilder<T extends BaseProduct> {
      Package preparePackage(T product);
}

class ProductAPackageBuilder implements PackageBuilder<ConcreteProductA> {

     @Override
    Package preparePackage(ConcreteProductA productA) {
        return new Package(productA.concreteAttA);
    }
}

class PackageManager {
    Map<String, PackageBuilder> packageBuilders;

    Package preparePackage(BaseProduct product) {
      return packageBuilders.get(product.productType).preparePackage(product);
    }
}

This code results in a downcast being made from BaseProduct when calling the prepare package. This also raises a compiler warning. I understand the disadvantages in downcasting and having calls to preparePackage not being statically typed. However, I'm also struggling to find a solution that's strictly better than this approach.

The obvious solution would be to move the preparePackage function inside the ConcreteProductA and expose the method in BaseProduct, so that I can take advantage of polymorphism. However, the thing I dislike about this approach is tha the product classes are mostly data objects, and the preparePackage function can contain lots of business logic. Ideally I'd like the product classes to be as thin as possible and contain just data and not a lot of behavior.

Is there any alternative that allows me to keep the product objects being data-only, and avoid this downcast? Would this be an acceptable case where downcast could be useful?

Aucun commentaire:

Enregistrer un commentaire