Justin_BSI has asked for the wisdom of the Perl Monks concerning the following question:

I was playing around with classes within Perl and trying to implement some of the patterns I've used in the past when I hit a road block. I'm still relatively new to Perl, and I can't seem to figure out what is going on here with this State pattern.
#### a driver for the car { package Driver; sub new { my $class = shift; my $vars = {}; $vars->{ALERTNESS} = 0; $vars->{STATE} = dstatenorm->new(); bless ($vars, $class); return $vars; } sub alertness { my $vars = shift; my $state = $vars->{STATE}; if(@_) { $vars->{ALERTNESS} = shift; } return $state->alertness( $vars->{ALERTNESS} ); } 1; } #### driver state normal { package dstatenorm; sub new { my $class = shift; my $vars = {}; $vars->{"NAME"} = "Normal"; bless ($vars, $class); return $vars; } sub alertness ($) { my $curAlertness = shift; return $curAlertness; } 1; }
When I call the "alertness" routine on the driver, I get dstatenorm=HASH(0x1832734). It looks like I'm getting close to the return I want, but I'm not sure where or how or if I have to dereference to make this work. Thanks in advance!

Update: Found it. I was shifting and the first value is the class itself. Shifting twice did the trick, so I guess I have to access @_ directly?

Replies are listed 'Best First'.
Re: Implementing State pattern
by rhesa (Vicar) on May 02, 2006 at 23:57 UTC
    You're calling alertness as a method, on the $state object. That means alertness() the sub receives $state the object as its first argument. You shift that into $curAlertness, and return it. You're also not doing anything with the other parameter that you pass in ($vars->{ALERTNESS}), so the $state object never gets updated.

    I suspect you want something like this for the implementation of alertness:

    sub alertness { my $self = shift; if( @_ ) { $self->{STATE} = shift; } return $self->{STATE}; }
Re: Implementing State pattern
by diotalevi (Canon) on May 02, 2006 at 23:25 UTC

    You didn't include an accessor in dstatenorm to fetch the NAME.

    package dstatenorm; ... sub name { my $self = shift @_; return $self->{NAME}; }

    Then in your code, request the name of the state.

    print $driver->alertness->name

    PS: don't use prototypes especially when writing object oriented code.

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      I'm not actually looking for the name of the state in the "alertness" routine, instead I am expecting a reply of the driver's alertness value. In the State pattern, the state makes modifications to (or performs functions on) the values of the "owning" class. For instance, if I made a state for the driver that was called "dstatetired" I could have the alertness routine return $curAlertness - 2;. I would set the current state through routines in the driver class.

      That being said, thank you for reminding me about the accessor and I will quit prototyping in my OO code (I'm used to Java, so pardon me.)