Perl OO Basic Object-oriented Perl is a small amount of additional syntax and semantics, added to the existing imperative features of the language. Damian Conway in “ Object Oriented Perl”
クラス / オブジェクト
package と bless
クラスは名前空間 (package) で定義
メソッドはクラス内のサブルーチン
bless でリファレンスの実体をオブジェクトに
package Dog; sub new { my($class, $name) = @_; bless { name => $name }, $class; } sub bark { my $self = shift; print “bark: $self->{name}”; } use Dog; my $dog = Dog->new(‘Snoopy’); $dog->bark();
継承
@ISA 配列で表現 (is-a)
base プラグマ使用を推奨
多重継承も可能
package Animal; sub run { my $self = shift; print “running!”; } package Dog; # @Dog::ISA = qw(Animal); use base qw(Animal); sub bark { } use Dog; my $dog = Dog->new(‘Snoopy’); $dog->bark(); # Dog::bark $dog->run(); # Animal::run
デストラクタ
DESTROY メソッド
オブジェクト消滅時に実行
リファレンスカウンタ
package Dog; sub DESTROY { my $self = shift; print “$self->{name}: Bye!”; } use Dog; my $dog1 = Dog->new(‘Scooby’); { my $dog2 = Dog->new(‘Scrappy’); } ! Scrappy: Bye! ! Scooby: Bye!
AUTOLOAD
未定義メソッドをキャッチ
アクセサの自動生成
メソッドのキャッシング・遅延ロード
package Dog; use vars qw($AUTOLOAD); my $accessors = { name => 1 }; sub AUTOLOAD { my $self = shift; (my $method = $AUTOLOAD) =~ s/.*://; return $self->{$method} if $accessors->{$method}; die “Unknown method: $method” } my $dog = Dog->new(‘Snoopy’); my $name = $dog->name();
演算子オーバーロード
overload プラグマを使用
5.6 以降は演算子が増えた
fallback オプション
package Dog; sub new { my($class, $name, $weight) = @_; # … } use overload q(“”) => &name, q(0+) => &weight, fallback => 1; sub name { shift->{name} } sub weight { shift->{weight} } my $dog = Dog->new(“Snoopy”, 13.5); printf “name is %s, weight is %f”, $dog, $dog;
UNIVERSAL
すべてのオブジェクトの祖先クラス
can(), isa() を定義
can() はメソッドのリファレンスを返す
AUTOLOAD と併用すると …
my $dog = Dog->new(); $dog->isa(‘Dog’); # true $dog->isa(‘Animal’); # true $dog->isa(‘Man’); # false my $bark = $dog->can(‘bark’); $man->$bark(); package UNIVERSAL; sub AUTOLOAD { my $self = shift; } すべてのクラスの未定義メソッドはここに !
可視性
public, private, protected
用意されてません
アトリビュートはアクセサメソッドで保護
private メソッドは _ を先頭に
paranoia な人は
caller() でチェック
Class::Fields, Attribute::Protected
Perl OO Advanced
Design Patterns (1/3)
Singleton Pattern
スタティック変数はレキシカル変数を利用
パッケージ変数に格納 (Class::Singleton)
package Printer; my $instance = Printer->new(); sub instance { $instance } package Printer; use base qw(Class::Singleton); sub _new_instance { … } オブジェクトが 1 つしかないことは保証できない
Design Patterns (2/3)
Decorator Pattern
AUTOLOAD を利用してメソッドを転送
Class::Decorator
Class::Delegate
package ReverseDecorator; sub new { my($class, $obj) = @_; bless { o => $obj }, $class; } sub AUTOLOAD { my($self, @args) = @_; (my $meth = $AUTOLOAD) =~ s/.*://; my @new_args = map reverse($_), @args; $self->{o}->$meth(@new_args); }
Design Patterns (3/3)
Class::* Modules
Class::Composite
Class::Prototype
Object:: PerlDesignPatterns
Perl でパターンやるなら必読
Mix-in
多重継承はダイアモンド型の問題あり
Exporter を利用して mix-in を実装
Ruby の Module に相当
mixin.pm (M.Schwern)
package Speakable; use base qw(Exporter); @EXPORT = qw(speak); sub speak { my $self = shift; print “my name: “, $self->name; } package Man; use Speakable; sub speak { my $self = shift; print “my name: “, $self->name; } 実装を借りてくるようなイメージ
AOP
Aspect Oriented Programming
Perl の OO は動的束縛
他クラスのメソッドを上書き
Aspect.pm
my $orig = Man->can(‘walk’); *Man::walk = sub { warn “Man::walk here”; goto &$orig; };
おまけ (1/2)
rubyisms .pm
Simon Cozens 作
Steal some features from Ruby
package Foo; use rubyisms; sub initialize { self->{things} = [ @_ ]; self->another_method; } sub my_method { if ($interesting) { … } else { super } } sub array_iterator (&@) { yield() for @_; } array_iterator { print $_[0], “
” } (“Hello”, “World”);
おまけ (2/2)
autobox .pm
use builtin datatypes as first-class objects
Perl 5.8.1 RC4 へのパッチ必要
use autobox; my $range = 10->to(1); my $ton = $range->[0]->mul(10); my $error = 3.14->minus(22/7); my $greeting = "Hello, World"->upper(); $greeting->to_lower(); $greeting->for_each(&char_handler); my $arr = [ @_ ]->map(...)->sort(...);
0 comments
Post a comment