Search code examples
moose

How to implement a class constant that is different for each subclass?


In my class hierarchy, I need a common attribute where each subclass needs to provide a different value that is constant for all objects of that class. (This attribute serves as a key to an existing hierarchy that I'm mirroring -- not the best OO design, but I need to preserve this link.)

One way to implement this is with attributes, like this:

package TypeBase;

use Moose::Role;

has type => (
    is => 'ro',
    isa => enum([qw(A B)]),
    builder => '_type',
    init_arg => nil,
    required => 1,
);

1;

#####

package TypeA;

use Moose;
with 'TypeBase';

sub _type { 'A' };

1;

#####

package TypeB;

use Moose;
with 'TypeBase';

sub _type { 'B' };

1;

Is there a better way to do this? I could just have requires 'type' in the base class, which each concrete class would have to provide, except that this loses me the type constraint that I had with the attribute route.


Solution

  • My solution is equivalent to yours in terms of the external interface. The main difference is the use of constant to better reflect what you are doing. (Note that TYPE can still be called like a method.) Because if is using requires it should also give you a compile-time rather than runtime error if you haven't implemented TYPE in one of your classes.

    package TypeBase;
    use Moose::Role;
    requires 'TYPE';
    
    package TypeA;
    use Moose;
    with 'TypeBase';
    use constant TYPE => 'A';
    
    package TypeB;
    use Moose;
    with 'TypeBase';
    use constant TYPE => 'B';