Pregunta

¿Cuál es la diferencia entre escribir subfunciones y ponerlo todo en un archivo frente a escribir paquetes?¿La orientación a objetos es mejor que la de procedimientos cuando se trata de Perl?

Básicamente buscando ejemplos de escenarios donde OO es mejor que procedimental.

¡Gracias!

¿Fue útil?

Solución

Primero, solo para aclarar, la diferencia entre procedimental y OO no es la misma que la diferencia entre poner todo su código en un archivo versus ponerlo en módulos separados. Puede tener módulos separados que estén llenos de funciones a las que llame de forma procedimental.

Donde el uso de módulos, OO o de procedimiento, es ventajoso es si el código se va a reutilizar o si es solo una base de código grande. Si tiene un CMS con 10 scripts CGI diferentes que hacen varias de las mismas cosas, como verificar la sesión de un usuario, entonces tiene sentido poner ese código en un módulo separado en lugar de reescribirlo en cada CGI. Si es una función de 20 líneas específica de ese script, déjela en el mismo archivo.

Si optar por OO o por procedimientos depende de lo que esté haciendo. La mayoría de la gente va a favorecer OO la mayor parte del tiempo en estos días. Estoy de acuerdo con ellos porque creo que te ayuda a pensar en tu código de manera lógica y a agrupar las cosas de una manera sensata que será fácil de administrar y actualizar más adelante.

Otros consejos

Me gusta poner la mayor cantidad de código posible en módulos. Lo bueno de los módulos es que puede usar las herramientas de prueba de Perl (probar y Probar :: Más) para escribir y administrar fácilmente las pruebas unitarias. Entonces, si casi todo su código está en módulos, casi todo se puede probar.

Cuando escribo un script, me gusta tener un contenedor delgado que analiza la configuración y las opciones de la línea de comandos en mi script (probablemente usando módulos como Config :: Any o Getopt :: Long). El script también contiene una subrutina usage. Luego agrego una subrutina main. main es muy simple:

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;
}

Prácticamente todas las subrutinas de soporte vivirían en uno o más módulos.

OOP es una buena forma de asociar datos y comportamiento. Esto puede hacer que el código sea más legible y reducir el desorden.

 $foo->eat_something( $sandwich )

es más fácil de entender que:

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

Toda la basura adicional está agrupada en prácticos atributos de objeto $foo y viaja sin saturar la sub llamada.

Por supuesto que podría hacer:

eat_something( $foo, $sandwich )

Donde $ foo es solo un hash ordinario de preferencias de sabor. De todos modos, esto es esencialmente lo que hace Perl OO. El invocante (objeto o nombre de clase) se pasa como primer argumento a cada método. Pierde conveniente espacio de nombres, herencia y llamadas a métodos dinámicos. De los tres costos, los espacios convenientes para los nombres serán los que más se pierdan. En mi opinión, la herencia está sobrevalorada y debe usarse solo en raras ocasiones. Las llamadas a métodos dinámicos pueden ser útiles por las mismas razones por las que las tablas de despacho son útiles.

No hay nada que no pueda hacer en OO Perl que no pueda hacer en Perl procedimental. Pero, OO hace que ciertas cosas sean muy convenientes.

Permítanme terminar reescribiendo mi guión mítico en estilo OO (me exageraré un poco con el OO, solo para ilustrar):

sub principal { my $ cfg= turno;

    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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top