Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re: object oriented Perl advice / constructor creation in child class

by haj (Vicar)
on Jul 10, 2018 at 09:09 UTC ( #1218227=note: print w/replies, xml ) Need Help??


in reply to object oriented Perl advice / constructor creation in child class

Well, your example doesn't actually show inheritance. Your constructor creates a "has-a" relationship, because your C1 objects will have one object of each of the classes A, B, C and D as attributes. This is a solid pattern in many cases, but it doesn't give you direct access to the methods of the four classes.

I'd say that today's perlish way to do OOP is Moose or its lightweight cousin Moo, and I definitely recommend those if you have several classes to inherit from. Here's a short example:

# A.pm package A; use 5.014; use Moo; sub say_hello { my $self = shift; my ($name) = @_; say "Hello, $name!"; } 1;
# C.pm package C; use 5.014; use Moo; has 'name' => (is => 'rw'); sub say_goodbye { my $self = shift; say 'Goodbye, ', $self->name, '!'; } 1;
# C1.pm package C1; use 5.014; use strict; use warnings; use Moo; extends 'C'; use A; has '_a' => (is => 'ro', default => sub { A->new() }, handles => [qw(say_hello)] ); 1;
Now you can do things like this:
use strict; use warnings; use C1; my $c = C1->new(name => 'John Doe'); $c->say_hello('World'); $c->say_goodbye;

So, your C1 objects have direct access to both the say_hello method from A.pm, and the say_goodbye method from C.pm.

  • Access to say_goodbye is done with inheritance, by the extends keyword of Moo. With inheritance you have access to all attributes and all methods of the parent class, so if you have more than one parent, you need to take care for possible conflicts.
  • Access to say_hello is achieved with method delegation. In that case, the A object needs to be created and has its own attributes, and the package must be loaded. On the plus side, you have control which methods of A you want to expose through the public interface of C1, and there's no problem with conflicts. You can, of course, always call the methods of A indirectly with $c->_a->say_hello('World').

Note that Moo (and Moose) will take care for object constructors: You don't write new methods!

If you want to do object inheritance without an object framework, you do it like this:

package C1; use parent (qw(A B C D));
However, in that case you need to take care for calling parent constructors and conflict resolution yourself, which is why I don't expand on this.

Replies are listed 'Best First'.
Re^2: object oriented Perl advice / constructor creation in child class
by smarthacker67 (Beadle) on Jul 11, 2018 at 06:16 UTC
    Yes, I agree its time to use Moose.

    My wild guess says

    Tie::Hash might be something I can utilize here but since never used before so finding it difficult use. Can Tie::Hash be used ?

      Sorry, but I don't see how Tie::Hash would help you here.

      In another reply you write that all your classes A to D already exist and have their own new methods, so Moo(se) inheritance (which makes Moose classes inherit from other Moose classes) isn't easily done either. As others have explained, Perl's method resolution with mro might help to some extent, but I doubt that it is worth the trouble. In any case you need to understand which of the methods you want to have available through the interface of C::C1 objects, especially with regard to their new methods.

      On whatever I've seen so far, I'd go for the delegation approach. The the existing classes don't have to be Moo(se) classes, and you explicitly implement the methods you want to make available through your C::C1 objects, and you can decide who should construct your A to D objects.

      package C::C1; # That's the perlish name for the module use File::FindLib 'lib'; use A; use B; use C; use D; sub new { return bless({ _a => A->new->bar, # I don't understand bar here _b => B->new->bar1, # nor bar1 here _c => C->new(), _d => D->new(), }, shift); } # now for any method of A: sub a_method_1 { my $self = shift; $self->_a->a_method 1(@_); } # etc # And for any method of B: sub b_method_1 { my $self = shift; $self->_a->b_method 1(@_); } # etc # Repeat for C and D, ad libidum.

      Maybe you want your users to read/write A to D? Here's an example for D:

      sub new_d { my $self = shift; if (@_) { $self->{_d} = D->new(@_); } return $self->{_d}; }
      Someone using C::C1 would write like this:
      use C::C1; my $c1 = C::C1->new; $c1->a_method_1(); # will execute A::a_method_1 $c1->b_method_1(); # will execute B::b_method_1 $c1->new_d(@params) # will execute $self->{_d} = D->new(@params)

      Moo or Moose can help to make your C/C1.pm more readable, because they have keywords for method delegation, as I've shown in my previous example. But before going deeper, I'd like to understand how the interface of your C/C1.pm should look like.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1218227]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (3)
As of 2023-09-24 00:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?