2009-11-14 21 views
7

Estoy usando los objetos "de adentro hacia afuera" de Damian Conway, como se describe en su maravilloso libro Perl Best Practices para construir una interfaz orientada a objetos a un sistema de seguridad en mi cliente. Me doy cuenta de la necesidad de usar métodos internos de ayuda dentro de mi módulo que normalmente designaría como "_some_method". Sin embargo, esto parece romper la encapsulación ya que pueden invocarse directamente a través del nombre del paquete. ¿Hay alguna forma de hacer estos métodos verdaderamente privados? A modo de ejemplo,¿Cómo se definen los métodos privados o internos en Perl orientado a objetos?

use SOD::MyOOInterface; 

my $instance1 = SOD::MyOOInterface->new(); 
$instance1->_some_method; #this produces an error: 
SOD::MyOOInterface::_some_method; # this results in a 
            # successful method call 

Obviamente no quiero la llamada directa de _some_method tenga éxito. ¿Hay alguna forma de garantizar esto?

+0

@Randal sí, lo siento, lo siento porque no estaba al tanto de esa regla. – ennuikiller

Respuesta

6

no utilice la PBP para las prácticas de objetos . Esto es muy viejo. De hecho, ahora las mejores prácticas con respecto a Perl y objetos se pueden encontrar en Moose, una herramienta casi imprescindible para Perl.

En resumen, la forma en que Perl difumina espacios de nombres y clases la mayoría de los métodos se pueden llamar estáticamente en la clase. Esto no es malo, simplemente no lo documente. Realmente no hay ninguna razón para querer sellar los métodos en la instancia. No tener métodos privados es un poco molesto, pero la convención de no confiar en los métodos no documentados es tan fuerte que ha sido suficiente para nuestra comunidad.

Un rasgo es efectivamente un rol (no permite creación de instancias) que se puede compilar en un objeto en tiempo de ejecución. Esto oscurecerá aún más el origen de los métodos de su usuario típico (porque no estarán en la clase original), pero tiene un costo en tiempo de ejecución. Ver MooseX::Traits para obtener más información sobre los rasgos.

El subrayado precedente es una gran convención para indicar además que el método es privado para los ojos.

Como última nota si realmente quiere empujar este problema, es posible que pueda crear una clase anónima con esos métodos utilizando Class :: :: MOP Class-> create_anon_class()

+0

Estoy de acuerdo. ¿Por qué es imposible que alguien llame a un método privado? Si no está documentado, no forma parte de la interfaz pública. Esto no solo rompe la encapsulación, sino que tampoco es respaldado por el autor. Pero, ¿por qué debería importarle el autor? Si decido usar mi computadora portátil como un martillo, esto claramente no es lo que las marcas de mi hardware pretendían y no lo soportarán ni repararán. Pero deberían hacer todo lo posible para evitar que lo haga o simplemente dejarme en mi estupidez. – mpeters

+0

Es porque algunas personas creen que deberían poder establecer una interfaz a través del código, para evitar que las personas se ahorquen, etc. etc. El guión bajo, el método no documentado es una convención que debes aprender, usarlo ni siquiera dispara una 'advertencia .' Algunos lenguajes como C# incluso inventan clases 'selladas' para impulsar este punto. –

+0

@EvanCarroll gracias, voy a estudiar el uso de Moose – ennuikiller

6

Tipo de. No se puede ocultar una subrutina que se instala en la tabla de símbolos, pero se puede utilizar una variable léxica para contener una referencia a una subrutina anónima:

package SOD::MyOOInterface; 

my $some_method = sub { ... } 

$some_method->(); 

Debido $some_method sólo es visible en el archivo de la aplicación de la clase, el la subrutina no se puede llamar externamente. El inconveniente es que no se puede llamar como un método, se debe llamar como una función. Si desea utilizarlo como un método que tendrá que pasar el objeto referencia explícita:

$some_method->($obj, @args); 
+0

@Micheal Sí, esperaba evitar la naturaleza "hackosa" de los escalares que contienen referencias a submarinos anónimos. – ennuikiller

+3

Si está usando objetos de adentro hacia afuera, ya está haciendo OO "pirateado". Esconder los métodos privados a través de referencias CODE parece encajar bastante bien. –

+0

@Michael, en realidad, una vez que te acostumbras a cada atributo como una función de hash de los objetos de adentro hacia afuera, ¡se vuelve bastante natural! – ennuikiller

1

La forma en que lidiar con esto es añadir algo como esto en el inicio del método:

my $self = shift; 
croak "Instance method called on class" unless ref $self; 

No es de ninguna manera encapsulación verdadera, pero sí significa que alguien que lo llama a través del paquete tendrá que pasar una instancia de objeto como primer argumento. En general, con Perl, considero que no tiene mucho sentido proteger a los usuarios malintencionados de mi API; esto me ayuda a detectar situaciones en las que accidentalmente trato de llamar al método como método de clase (lo que sucede más a menudo de lo que me gustaría). admitir).

Personalmente, creo que la convención de guión bajo + documentar claramente el método como privado (o no documentarlo para que no aparezca en el POD) es suficiente para el uso en el mundo real. Esta es también la forma en que funciona en Python. Es parte de language philosophy de no restringir a los usuarios.

módulo

Un Perl prefiere que se quede fuera de su sala de estar, ya que no fueron invitados, no porque tenga una escopeta ...

10
package Foo; 

## declare inside-out hashes here: 

my %attr_a; 
my %attr_b; 

## declare private methods here 

my $private_1 = sub { 
    my $self = shift; 
    # can use $attr_a{$self} here... 
    ... 
}; 

my $private_2 = sub { 
    my $self = shift; 
    ... 
}; 

## public methods here 

sub new { ... } 

sub public_1 { 
    my $self = shift; 
    # can access attributes here 
    # can call private methods too, with slightly odd syntax: 
    my $result = $self->$private_1(@args); 
    ... 
} 

1; 
+0

Acabo de descubrir este patrón en el libro "Camel" recientemente después de muchos años de programación de Perl, Me sorprende que no se use más. Pero creo que todas las respuestas con respecto a lo que se ha convertido en la norma en la comunidad responden eso. ;-) – drnewman

Cuestiones relacionadas