Pergunta

Qual é a diferença entre escrever subfunções e colocar tudo em um arquivo em vez de escrever pacotes?É orientado a objetos melhor do que procedural quando se trata de Perl?

Basicamente, procurando por exemplos de cenários onde OO é melhor do que procedural.

Obrigado!

Foi útil?

Solução

Primeiro, apenas para esclarecer, a diferença entre procedural e OO não é a mesma que a diferença entre colocar todo o seu código em um arquivo e colocá-lo em módulos separados. Você pode ter módulos separados cheios de funções que você chama proceduralmente.

Onde usar módulos, OO ou procedurais, é vantajoso é se o código for reutilizado ou se for apenas uma grande base de código. Se você tiver um CMS com 10 scripts CGI diferentes que fazem várias das mesmas coisas, como talvez verificar uma sessão de usuário, então colocar esse código em um módulo separado em vez de reescrevê-lo em cada CGI faz sentido. Se for uma função de 20 linhas específica para esse script, deixe-a no mesmo arquivo.

Escolher OO ou procedural depende do que você está fazendo. A maioria das pessoas prefere OO na maior parte do tempo atualmente. Eu concordo com eles, pois acho que isso ajuda você a pensar sobre o seu código de forma lógica e agrupar as coisas de uma maneira sã, que será fácil de gerenciar e atualizar mais tarde.

Outras dicas

Gosto de colocar o máximo possível do meu código em módulos. O bom dos módulos é que você pode usar as ferramentas de teste do Perl (provar e Test :: More) para escrever e gerenciar facilmente os testes de unidade. Portanto, se quase todo o seu código está em módulos, quase todo ele pode ser testado.

Quando escrevo um script, gosto de ter um wrapper fino que analisa a configuração e as opções de linha de comando em meu script (provavelmente usando módulos como Config :: Any ou Getopt :: Long). O script também contém uma sub-rotina usage. Em seguida, adiciono uma sub-rotina main. main é muito simples:

sub main {
    my $cfg = shift;

    my @collected_data;

    for my $file ( @{ $cfg->{files} ) {
        eval {
            my $fh = get_handle_from_file($file);

            my $xyz_data = parse_xyz_data( $fh );

            push @collected_data, extract_data( $xyz_data, $cfg->{filter} );

            1;
        } or do {
            my $e = $@;
            $e = "an unknown error occurred" unless defined $e;

            warn "Error parsing '$file': $e\n";
        };        
    }

    my %summary_data = summarize_data( @collected_data );

    write_summary( $cfg->{summary_target} );

    return;
}

Quase todas as sub-rotinas de suporte estariam em um ou mais módulos.

OOP é uma boa maneira de associar dados e comportamento. Isso pode tornar o código mais legível e reduzir a desordem.

 $foo->eat_something( $sandwich )

é mais fácil de entender do que:

 eat_something( $sandwich, $likes_salty, $likes_sour, $likes_sweet, $likes_spicy );

Toda a porcaria extra é agrupada em atributos de objeto $foo úteis e viaja sem atrapalhar a sub chamada.

Claro que você poderia fazer:

eat_something( $foo, $sandwich )

Onde $ foo é apenas um hash comum de preferências de sabor. Isso é essencialmente o que o Perl OO faz. O invocante (nome do objeto ou classe) é passado como o primeiro argumento para cada método. Você perde namespacing conveniente, herança e chamadas de métodos dinâmicos. Dos três custos, os espaços de nomes convenientes farão mais falta. IMO, a herança é superestimada e deve ser usada apenas raramente. Chamadas de método dinâmico podem ser úteis pelos mesmos motivos pelos quais as tabelas de despacho são úteis.

Não há nada que você não possa fazer em Perl OO que não possa ser feito em Perl procedural. Mas, OO torna certas coisas muito convenientes.

Deixe-me encerrar reescrevendo meu roteiro mítico no estilo OO (vou exagerar um pouco no OO, apenas para ilustração):

sub main { meu $ cfg= shift;

    my $cd = Data::Collection->new();

    for my $file ( $cfg->files ) {
        eval {

            # skip the step of creating a handle first.  The parsing object
            # can take a file and get a handle or could be passed a handle.               

            my $xyz_parser = File::XYZ::Parse->new( file => $file );

            # The parser returns an XYZ::Data object

            my $xyz_data = $xyz_parser->parse;

            $cd->add_data( $xyz_data->extract_data( $cfg->filter );

            1;
        } or do {
            my $e = $@;
            $e = "an unknown error occurred" unless defined $e;

            warn "Error parsing '$file': $e\n";
        };        
    }

    # Skip the step of separate summarization, since the cd object can check if
    # the summary has been done, and if not generate and cache it as needed.

    $cd->write_summary( $cfg->summary_target );

    return;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top