Loading

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();
    
    

输出

image

参考

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

posted @ 2021-10-09 10:30  Test002  阅读(8)  评论(0)    收藏  举报