HasTraits: Interfaces vs. Subclassing vs. ABC design patterns

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

HasTraits: Interfaces vs. Subclassing vs. ABC design patterns

Adam Hughes
Hello,

I'm building a small object-oriented library for drawing shapes (numpy arrays for use in scikit image) with basic metadata to facilitate patterned drawing.  Because I want to strictly type most of these metadata attributes, Traits is saving me a lot of hassle.  One area that I'm struggling with; however, is in the design choice to implement interfaces strictly vs. subclassing.  

For a simple example, let me define a Particle Interface:   

class Particle(Interface):
    """   """
    center = Tuple(0.0, 0.0)    
    ptype = 'generic particle'
    pnum = Int(1)

    # Set by the draw() method
    rr = Array
    cc = Array
    
    def draw(self, image):
        """ description ... """
        self.rr, self.cc = ...

So here is the design problem I'm having--  

Consider the ptype trait.  I want this trait to be highly exposed, so that any further Particle types specify their ptype. (EG):

class Circle(HasTraits):
    ptype = 'circle'

In this case, implementing the interface works nice.  Had I subclassed, it would be easy to forget that this trait is going to default to "generic particle", which I want to avoid.

On the other hand, traits like rr, cc and center, are fairly generic defaults that any implementing class would use these defaults.  Therefore, subclassing would allow me to effectively "bury" these so that users writing custom subclasses don't need to worry about boilerplating them.  When I use implementation, I need to explictly redefine these for every class.  While this is not a problem, it adds a lot of boilerplate.

One compromise might be to split the difference and make an interface that implements variable traits like "ptype", and then make a general class to default most of the non-changing traits like "rr" and "cc", then directly subclass this.  Something like:

class Particle(Interface):
    """   """
    center = Tuple(0.0, 0.0)    
    ptype = 'generic particle'
    pnum = Int(1)

   def draw(self, ...)
    ...

class GenericParticle(HasTraits):
    implements(Particle)
    # Set by the draw() method
    rr = Array
    cc = Array

class Circle(GenericParticle):
    ...

Would doing so still preserve the interface implementation?

I figured I'm not the first to encounter this quandry, so any insights would be quite helpful.

Thanks.


--
Adam Hughes
Physics Ph.D Candidate
George Washington University

_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev