How to wrap a concrete subclass within the abstract/final design pattern

1 day ago 4
ARTICLE AD BOX

I'm using the equinox library for a project, written in python.

This library is used to define dataclasses and strongly recommends to use the abstract/final pattern when designing these classes.

I understand most of it, but there is this part where I am uncertain what the language means:

What about when you have an existing concrete class that you want to tweak just-a-little-bit? In this case, prefer composition over inheritance. Write a wrapper that forwards each method as appropriate. This is just as expressive, and means we keep these readable type-safe rules.

So for a concrete example, suppose I have the following class structure:

from abc import abstractmethod import jax.numpy as jnp from jaxtyping import Float import equinox as eqx class AbstractShape(eqx.Module): area: eqx.AbstractVar[Float] @abstractmethod def compute_area(self): raise NotImplementedError class Ellipse(AbstractShape): area: Float major_axis: Float minor_axis: Float def __init__(self, major_axis, minor_axis): self.major_axis = major_axis self.minor_axis = minor_axis self.area = self.compute_area() def compute_area(self): return jnp.pi * self.major_axis * self.minor_axis # How to define a circle class according to the abstract/final pattern? ...

My immediate instinct is to write a Circle class as a subclass of the Ellipse class. But this is forbidden by the recommended pattern; you can never subclass a concrete class in the abstract/final design pattern.

So what does it mean to [w]rite a wrapper that forwards each method as appropriate in this context? How would I wrap Ellipse transparently to obtain a Circle class (for instance by providing the radius parameter)?

Read Entire Article