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

I'm seeking some help about object Orientated Programming in Perl. I am not new to Perl and have written a number of standalone packages with methods but never really using OOP techniques. If I use some incorrect terminolgy please put me right.

I have a class called User and a constructor which creates a User object given the username. The User class has a login method which logs you into a system given the password and saves an instance variable which is the unique session id required to perform any further actions when logged in. ok so far.

Each user can have multiple bank accounts so the User class also has a method to return a list of accounts once logged in.

Lastly, the User class has an open_account method which opens a bank account given the account number and returns a User::Account object.

The User::Account object returned can be used to say query the balance so it has a balance method. However, all communication with the server needs to be done using a single call to the server which is passed an API name and all calls to the server once logged in need to pass the session id (lets call this method "get" which User::login would also use but this would be the one case where the session id is not required).

Logically, to me, the "get" method belongs in the User class as it is common to all User::*. This means the User::Account::balance method needs to call User::get but User::Account does not know the session id or server info that User::login obtained.

How would one share the session id and server info obtained in User::new and User::login and store in instance variables of User with User::Account?

Package User sub new { my ($class, $username) = @_; my $self->{username} = $username; # connect to server and store connection details in $self->{server} bless $self, $class; } sub get { my $self = shift; # call server using $self->{server} adding session_id if we have one } sub login { my $self = shift; $self->get('login'); # will store session_id in User object } sub get_accounts { my $self = shift; return $self->get('accounts'); } sub open_account { my ($self, $account_id) = @_; my $self->{account} = User::Account->new(account_id); return $self->{account}; } Package Account our @ISA = qw(User); sub balance { # needs to call User::get but does not have session id or server inf +o }

Replies are listed 'Best First'.
Re: Perl OOP help for OOP newbie
by Anonymous Monk on Jun 01, 2011 at 18:59 UTC

    You probably don't want to have Account be a sub-class of User. That is, you don't want to have our @ISA = qw(User). Instead, you probably should have an instance variable in each Account that references the User object that it is associated with.

    Also, since you can have several accounts for each user, it probably doesn't make sense to have $self->{account} = User::Account->new($account_id);

    You probably want to have something like:
    package User; # ... sub open_account { my ($self, $account_id) = @_; return User::Account->new($self, $account_id); } package Account; sub new { my ($class, $user, $account_id) = @_; my $self = { user => $user, account_id = $account_id }; bless $self, $class; } sub balance { my $self = shift; # now you have $self->{user} for the user object # and $self->{account_id} }

      Thanks for your reply. I don't get your comment "Instead, you probably should have an instance variable in each Account that references the User object that it is associated with." Surely, User::Account belongs to User? and I don't understand how you'd create an instance variable in each Account that references the User object - how do you do that? Presumably you are referring to the $self in "return User::Account->new($self, $account_id); ".

      I'll work on your idea and see where I get.

        Inheritance is for "is a" relationships. For instance, a BMW "is a" SportsCar, so BMW could inherit from SportsCar. Now let's try it with your class: An Account "is a" User. That isn't true, so Account would not inherit from User.

        "Composition" is for "has a" relationships. For instance, a User "has a(n)" Account. In your case, composition would involve assigning an Account object to a User variable. If your User object uses a hash internally, then one key in the hash could be called ACCOUNTS, and its value could be a reference to an array. The array would contain various Account objects.

        If a user has multiple accounts, I'd suggest this:
        package User; sub new { my ($class, $username) = @_; my $self =(username=> $username, accounts=>{} , # No accounts for a +new user server=> {Some server connection info} ); bless $self, $class; } sub open_account { my ($self, $account_id) = @_; return $self->accounts->{$account_id} = User::Account->new($self, $ac +count_id); } # accessor for accounts.. sub get_account{ my ($self,account_id) = @_; return $self->accounts->{account_id}; }

                    "XML is like violence: if it doesn't solve your problem, use more."