350 likes | 471 Views
This guide introduces Object-Oriented Programming (OOP) in Perl through the Moose object system. Unlike traditional procedural programming, which relies on simple variables and subroutines, OOP allows data to be encapsulated within objects that know their own methods. We'll explore key OOP concepts such as classes, objects, attributes, and methods. You'll learn how to define a class, create instances, and manipulate attributes using accessors and mutators. By adopting Moose, Perl developers gain enhanced power and flexibility in their code.
E N D
Moose: A Postmodern Object System for Perl Stuart Skelton
What is OOP? “Traditional” programming is procedural Subroutines work on variables my $distance = distance($point1,$point2); Variables are dumb Just stores for data
What is OOP? Object Oriented programming inverts this Variables are objects Objects can carry out certain processes Called methods my $distance = $point1->distance($point2); Objects are intelligent Objects know what methods they can carry out
Some Concepts A Class is a type of intelligent variable (blueprint of an object) e.g. Dog An Object is an instance of a class e.g. Amber An Attribute is a piece of data in an object e.g. KennelClubName A Method is an action that an object does e.g. Bark
Methods Methods can be either class methods or object methods Class methods are called on a class my $amber = Dog->new; Object methods are called on an object $amber->bark;
Constructors All classes need a constructor method Creates a new object of that class Usually a class method Often called new my $amber = Dog->new; my $hunter = new Dog;
Accessors & Mutators Access object attributes with an accessor method say “The kennel club name of Amber is “,$amber->get_kennel_club_name; Change an attribute with a mutator method $amber->set_age( $amber->get_age + 1);
Accessor & Mutators Accessors and mutators are often the same method say “The kennel club name of Amber is “, $amber->kennel_club_name; $amber->age($amber->age + 1); Checks number of parameters Reacts appropriately
Basic Anatomy Package Classname; atribute1 attribute2 method1 method2 1;
package PointTP; sub new { my $class = shift; my $self = { x => shift, y => shift, }; bless $self, $class; return $self; } sub set_x { my ( $self, $x ) = @_; $self->{x} = $x if defined($x); } sub get_x { my( $self ) = @_; return $self->{x}; } sub set_y { my ( $self, $y ) = @_; $self->{y} = $y if defined($y); } sub get_y { my( $self ) = @_; return $self->{y}; }
#!/usr/bin/perl use Modern::Perl ; use PointTP ; my $point1 = Point->new(1,2) ; say $point1->get_x() ; # prints 1 #change the x-coord $point1->set_x(-10); say $point1->get_x() ; # prints -10
sub set_x { my ( $self, $x ) = @_; $self->{x} = $x if defined($x); } sub get_x { my( $self ) = @_; return $self->{x}; } sub x { my ($self, $new_x) = @_; if (defined $new_x) { $self->{x} = $new_x; } return $self->{x};}
#!/usr/bin/perl use Modern::Perl ; use Point ; my $point1 = Point->new(1,2) ; say $point1->x() ; # prints 1 #change the x-coord $point1->x(-10); say $point1->x() ; # prints -10
Moose Moose is a Modern Object System for Perl 5 Based on Perl 6 object system More powerful More flexible Easier
Simple Moose Class package Point;use Moose;has x => ( is => 'rw', isa => 'Num', required => 1); has y => ( is => 'rw', isa => 'Num', required => 1);no Moose;__PACKAGE__->meta->make_immutable;
What's Going On? use Moose; Loads Moose environment Makes our class a subclass of Moose::Object Turns on use strict and use warnings
Declarative Attributes has x => ( is => 'rw', isa => 'Num', required => 1); Creates an attribute called 'x' Makes it read/write Must be a number Is required
Housekeeping Moose classes carry a lot of baggage We can (and should) turn some of it off no Moose; Remove Moose exports from your namespace See also namespace::autoclean __PACKAGE__->meta->make_immutable; No more changes to class definition Performance improvements
Required Attributes By default Moose attributes are optional Make them mandatory with required has x => ( ... required => 1,); my $point1 = Point->new; “Attribute (x) is required at constructor Point::new”
Attribute Defaults Set a default for missing attributes has accuracy => ( default => 0.5,); Or a subroutine reference has accuracy => ( default => sub { rand },);
Attribute Builder Define a builder method instead of a default subroutine has accuracy => ( builder => '_build_accuracy',); sub _build_accuracy { return rand;} Easier to subclass
Read/Write Attributes Moose creates methods to access/alter attributes $point1->x(-1);say $point1->x; The 'is' property controls how they work 'rw' : read and write 'ro' : read only
Read/Write Attributes But PBP says use get_* and set_* has x => ( .... , reader => get_x, Writer => set_x, ); use MooseX::FollowPBP; Rule of Thumb, pick a style and stick with it
Other Methods Not all methods are constructors or accessors/mutators Write other methods as usual First parameter is object reference
Other Methods package Point;...sub distance { my $self = shift ; my $newpoint = shift ; return unless $newpoint->isa('Point') ; return sqrt( ($self->x - $newpoint->x)**2 + ($self->y - $newpoint->y)**2 ) ; }
Using the Point #!/usr/bin/perl use Modern::Perl ; use Point ; my $point1 = Point->new(x=>-7,y=>-4) ; my $point2 = Point->new(x=>17,y=>6) ; say join ' ' , 'The Distance between point 1', $point1->toString , 'and point 2', $point2->toString, 'is' , $point1->distance($point2) ; # prints 'The Distance between point 1 (-7,-4) and point 2 (17,6) is 26'
Sub Classing A subclass is a specialisation of a superclass More specific behaviour New attributes New methods Overriding superclass methods and attributes
package Point3D; use Moose; extends 'Point' ; has z => ( is => 'rw', isa => 'Num', required => 1 ); override distance => sub { my $self = shift; my $newpoint = shift; return unless $newpoint->isa('Point3D') ; my $distance2d = super(); return sqrt( $distance2d**2 + ($self->z - $newpoint->z)**2 ) ; };
use Modern::Perl ; use Point3D ; my $point1 = Point3D->new(x=>-7,y=>-4,z=>3); my $point2 = Point3D->new(x=>17,y=>6,z=>2.5); say join ' ' , 'The Distance between point 1', $point1->toString , 'and point 2', $point2->toString, 'is' , $point1->distance($point2) ; # prints 'The Distance between point 1 (-7,-4,3) and point 2 (17,6,2.5) is 26.0048072478917'
Other Atrribute types any Item Bool Maybe[`a] Undef Defined Value Str Num Int ClassName RoleName Ref ScalarRef[`a] ArrayRef[`a] HashRef[`a] CodeRef RegexpRef GlobRef FileHandle Object
package Farm; use Moose; has 'animals' => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[Animal]', default => sub { [] }, handles => { all_animals => 'elements', add_animal => 'push', find_animal => 'first', get_animal => 'get', count_animals => 'count', has_animals => 'count', has_no_animals => 'is_empty', sorted_animals => 'sort', }, ); no Moose; 1;
package Galaxy; use Moose; has 'planets' => ( traits => ['Hash'], is => 'ro', isa => 'HashRef[Planets]', default => sub { {} }, handles => { set_planets => 'set', get_planets => 'get', has_no_planets => 'is_empty', num_planets => 'count', delete_planets => 'delete', }, ); no Moose; 1;
Further Information Moose does a lot more We have only scratched the surface Good documentation CPAN Moose::Manual::* Moose::Cookbook::* No good book yet