perl面向对象编程的实现方式
基于匿名哈希表的缺点
- 无法为属性提供一种访问限制,限制外部对内部属性的访问和改变。
- 在处理大规模实例的情况下,系统的内存开销较大。
面向对象的概念
- 实例(instance): 一个类的实例化实现
- 标识:每个对象的实例都需要一个可以唯一标识这个实例的标记。
- 实例属性:一个对象就是一组属性的集合。
- 实例方法:所有存取或更新对象某个实例一条或者多条属性的函数的集合。
- 类属性: 属于一个类中所有对象的属性。不会只在某个实例上发生改变。
- 类方法:无须属性就能工作的类方法。
基于匿名散列表的方法
package Person;
sub new {
my ($class) = @_;
my $data = {};
$class = ref($class) || $class;
return bless $data, $class;
}
sub method {
my ($self) = @_;
}
# 使用方式
my $person = Person->new();
# 需要注意的是使用 -> 如果以 Person::new的方式调用,将不会传递$class 参数。
# 之后方法的调用均为 $person->method();
继承语法
use Person;
package Employee;
use base qw(Person);
sub new {
my ($class) = @_;
my $data = {};
$class = ref($class) || $class;
return bless $data, $class;
}
# 使用方法
my $e = Employee->new();
$e->method();
# 这样调用method, 就会调用到父类的method方法。
父类调用子类方法的技巧
package A;
sub func {
my ($class) = @_;
$class = ref($class) || $class;
my $data = {};
return bless $data, $class
}
sub a_func1 {
my ($self) = @_;
$self->b_func1();
}
sub b_func1{
my ($self) = @_;
}
package B;
use base qw(A);
sub b_func1 {
my ($self) = @_;
}
# 使用方法
$a = B->func();
$a->a_func1();
# 需要注意的是,尽管func方法定义在A模块中,但是传递给func函数的$class 函数却是B模块,所有实际上跟$a绑定的模块是B模块。所以
#如果$a->a_func1(); 尽管A模块也定了b_func1方法,但是调用的是B模块中的b_func1方法。
基于数组的方法
实现原理
为每个类的实例属性分配一个数组,每一个新的实例将是跨越所有数组列的一个切片,每次需要实例化一个新的对象,new函数将会被调用,一个新的逻辑行将被分配,新的实例的实例属性将以新的行偏移量插入到相应的属性列当中去。
代码清单
-
统一的处理类,用于自动注入代码。
package PObj; use Data::Dumper; use base 'Exporter'; our @EXPORT_OK = qw(define_attribute); sub define_attribute { my $package = shift @_; foreach my $attribute (@_) { my $define_attribute_code = qq { package $package; \@{"$package::$attribute"} = (); }; my $define_get_attribute_code = qq { package $package; print(get_$attribute); sub get_$attribute { my (\$id) = \@_; my \$data = \@{"$package::$attribute"}[\$\$id]; print "id=> \$\$id get $attribute = \$data\n"; } }; my $define_set_attribute_code = qq { package $package; sub set_$attribute { my (\$id, \$attribute) = \@_; \@{"$package::$attribute"}[\$\$id] = \$attribute; print "id=> \$\$id set $attribute = \$attribute\n"; } }; eval $define_attribute_code; print($define_attribute_code) if($@); eval $define_get_attribute_code; print($define_get_attribute_code) if($@); eval $define_set_attribute_code; print($define_set_attribute_code) if($@); } } 1; -
调用接口自动生成代码,并实现自己的代码.
package Person; use PObj qw(define_attribute); my $is_init = 0; my $CURRENT_ID = 0; sub get_next_id { $CURRENT_ID++; return $CURRENT_ID - 1; } sub new { my ($class, $name, $age) = @_; $class = ref($class) || $class; if($is_init == 0){ define_attribute($class, "name", "age"); $is_init = 1; } my $id = get_next_id(); my $self = bless \$id, $class; $self->set_name($name); $self->set_age($age); return $self; } sub method { my ($self) = @_; $self->get_name(); } 1;备注:
当然,你可以把获取ID的值,放到
PObj中。实际使用中,还应该处理析构函数,因为类的属性存放在数组中,对象析构时应该释放对应的位置数据。对象唯一性ID 值也不应该是简单的递增。
-
使用方式
BEGIN { push @INC, "/root/zhuo"; } use Person; my $a = Person->new('A', 100); my $b = Person->new('B', 200); print("--------------------\n"); $a->get_name(); $a->get_age(); $b->get_name(); $b->get_age(); print("自定义函数\n"); $a->method();
输出

参考
https://www.cnblogs.com/A-Song/archive/2012/04/12/2443541.html

浙公网安备 33010602011771号