How do I interact with a Perl object that has a hash attribute?

前端 未结 3 1613
忘掉有多难
忘掉有多难 2021-02-10 20:22

I have a class with several variables, one of which is a hash (_runs):

sub new
{
    my ($class, $name) = @_;
    my $self = {
        _name => $name,
                


        
3条回答
  •  南笙
    南笙 (楼主)
    2021-02-10 21:14

    First, you have to figure out what you actually want to return and what you want the higher level to be able to do with the data.

    If you want to return a copy of the data or any changes to the returned data don't affect the copy in the object, you can't do the simple solutions that the other answers tell you because they return shallow copies which will still share internal references. You need to make a deep copy then return the disconnected data structure. Storable makes this easy with dclone:

     use Storable qw( dclone );
    
     sub some_method {
          my( $self, ... ) = @_;
          ...;
          my $clone = dclone( $self->{_runs} );
          $clone;
          }
    

    If you want the higher level to change the object by changing the returned data structure, just return the reference that you already store. You don't need to do anything fancy for that:

     sub some_method {
          my( $self, ... ) = @_;
          ...;
          $self->{_runs};
          }
    

    Beyond that, it's your job to create an interface so that people don't have to think about your data structure at the higher level. You encapsulate everything so your implementation details don't show themselves. That way, you can change the implementation without disturbing the higher level code (as long as the interface is stable).

    You create a runs method that returns a list of runs:

     sub get_run_keys {
          my( $self ) = @_;
    
          keys %{ $self->{_runs} };
          }
    

    Or maybe you just want the values:

     sub get_run_values {
          my( $self ) = @_;
    
          values %{ $self->{_runs} };
          }
    

    Or maybe the whole thing:

     sub get_run_hash {
          my( $self ) = @_;
    
          $self->{_runs}; # subject to the cloning stuff I mentioned earlier
          }
    

    When you want to get the values for a particular run, you access it through another method:

     sub get_run {
          my( $self, $key ) = @_;
    
          $self->{_runs}{$key};
          }
    

    Setting a run value is similar:

     sub set_run {
          my( $self, $key, $value ) = @_;
    
          $self->{_runs}{$key} = $value;
          }
    

    Now your higher level doesn't know anything about the infrastructure, and the method names describe what you are trying to do instead of how the infrastructure has to do it:

     foreach my $key ( $self->get_run_keys ) {
         my $run = $self->get_run( $key );
         ...;
         $self->set_run( $key, $new_value );
         }
    

    Object-oriented design is a big topic, and there is a lot you can do. This is just enough to get you started. You can wrap other operations too:

     sub does_run_exist {
          my( $self, $key ) = @_;
    
          exists $self->{_runs}{$key};
          }
    
     sub delete_runs {
          my( $self, @keys ) = @_;
    
          delete $self->{_runs}{$key} foreach my $keys ( @keys );
          }
    
     sub reset_runs {
          my( $self, $key ) = @_;
    
          $self->{_runs} = {};
          }
    

提交回复
热议问题