First, you need to find out what you really want to return, and what you want the higher level to work with data.
If you want to return a copy of the data or any changes to the returned data, do not affect the copy of the object, you cannot make simple decisions that other answers will tell you, because they return small copies, which will still have common links. You need to make a deep copy and then return the disconnected data structure. Storable makes it easy to work with dclone :
use Storable qw( dclone ); sub some_method { my( $self, ... ) = @_; ...; my $clone = dclone( $self->{_runs} ); $clone; }
If you want a higher level to modify the object by changing the structure of the returned data, just return the link that you already store. You do not need to do anything for this:
sub some_method { my( $self, ... ) = @_; ...; $self->{_runs}; }
In addition, your task is to create an interface so that people cannot think about your data structure at a higher level. You encapsulate everything so that your implementation details are not shown. Thus, you can change the implementation without breaking the code of a higher level (as long as the interface is stable).
The runs method is created, which returns a list of runs:
sub get_run_keys { my( $self ) = @_; keys %{ $self->{_runs} }; }
Or maybe you just need the values:
sub get_run_values { my( $self ) = @_; values %{ $self->{_runs} }; }
Or maybe all:
sub get_run_hash { my( $self ) = @_; $self->{_runs};
If you want to get values for a specific run, you will access it using another method:
sub get_run { my( $self, $key ) = @_; $self->{_runs}{$key}; }
Setting the trigger value is similar to:
sub set_run { my( $self, $key, $value ) = @_; $self->{_runs}{$key} = $value; }
Now your higher level knows nothing about the infrastructure, and the method names describe what you are trying to do, and not how the infrastructure should 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 you can do a lot. This is enough to get you started. You can also wrap other operations:
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} = {}; }