2009-11-14 13 views
7

Używam obiektów typu "inside-out" Damiana Conwaya, tak jak opisano jego wspaniałą książkę Perl Best Practices, aby skonstruować obiektowy interfejs do systemu bezpieczeństwa u mojego klienta. Natrafiam na potrzebę użycia wewnętrznych metod pomocniczych w moim module, które normalnie określam jako "_some_method". Jednak wydaje się to przełamać enkapsulację, ponieważ można je wywołać bezpośrednio za pomocą nazwy pakietu. Czy istnieje sposób na uczynienie tych metod naprawdę prywatnymi? Na przykład:Jak zdefiniować prywatne lub wewnętrzne metody w Perlu zorientowanym obiektowo?

Oczywiście nie chcę, aby bezpośrednie wywołanie metody _some_method się powiodło. Czy istnieje sposób na zagwarantowanie tego?

+0

@Randal Tak, zrobiłem, przykro mi z tego powodu, że nie wiedziałem o tej zasadzie. – ennuikiller

Odpowiedz

6

Nie używaj PBP praktyk obiektowych . To jest bardzo stare. W rzeczywistości teraz najlepsze praktyki dotyczące Perla i obiektów można znaleźć w Moose, prawie niezbędnym dla Perla.

W skrócie, sposób, w jaki Perl zaciera przestrzenie nazw i klasy, może zostać wywołany statycznie w klasie. To nie jest złe, po prostu nie dokumentuj tego. Naprawdę nie ma powodu, aby chcieć przypieczętować metody do instancji. Brak prywatnych metod jest irytujący, ale konwencja polegania na nieudokumentowanych metodach jest tak silna, że ​​wystarczy dla naszej społeczności.

Cecha jest faktycznie rolą (nie pozwala na tworzenie instancji), która może zostać skompilowana do obiektu w czasie wykonywania. Spowoduje to dalsze zaciemnienie pochodzenia metod od typowego użytkownika (ponieważ nie będą one w oryginalnej klasie), ale będzie to koszt runtime. Aby uzyskać więcej informacji o cechach, zobacz numer MooseX::Traits.

Podkreślenie podkreślenia jest świetną konwencją, która pozwala stwierdzić, że metoda jest prywatna dla oczu do podglądania.

Jako ostatnia uwaga, jeśli naprawdę chcesz, aby wcisnąć ten problem, może być w stanie utworzyć anonimową klasę z tych metod przy użyciu Class :: :: MOP wykładowa> create_anon_class()

+0

Zgadzam się. Dlaczego uniemożliwić komuś prywatną metodę? Jeśli nie jest to udokumentowane, nie jest częścią publicznego interfejsu. Nie tylko to przełamuje hermetyzację, ale także wyraźnie nie będzie wspierane przez autora. Ale dlaczego autor miałby się tym przejmować? Jeśli zdecyduję się użyć mojego laptopa jako młotka, to nie jest to przeznaczenie mojego sprzętu i nie będą go wspierać ani naprawiać. Ale czy powinni zrobić coś, co przeszkodzi mi w tym, lub po prostu zostawić mnie na moją głupotę. – mpeters

+0

To dlatego, że niektórzy ludzie wierzą, że powinni być w stanie ustanowić interfejs za pomocą kodu, aby powstrzymać ludzi przed powieszeniem się itp. Podkreślenie, nieudokumentowana metoda jest konwencją, której musisz się nauczyć, używanie jej nawet nie powoduje ostrzeżenia . "Niektóre języki, takie jak C#, nawet wymyślają klasy" zapieczętowane ", aby pchnąć ten punkt. –

+0

@EvanCarroll dzięki, przyjrzę się za pomocą Moose – ennuikiller

6

Sortuj. Nie da się ukryć podprogram, który jest zainstalowany w tablicy symboli, ale można użyć zmiennej leksykalne posiadać odniesienie do anonimowej procedury:

package SOD::MyOOInterface; 

my $some_method = sub { ... } 

$some_method->(); 

Ponieważ $some_method jest widoczny tylko w pliku wykonawczego do klasy, podprogramu nie można nazwać zewnętrznie. Wadą jest to, że nie można go nazwać jako metody, musi być wywołana jako funkcja. Jeśli chcesz używać go jako metody musisz przekazać referencję do obiektu wyraźnie:

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

@Micheal Tak, miałem nadzieję uniknąć "hakowatej" natury skalarów z referencjami do anonimowych subków! – ennuikiller

+3

Jeśli używasz wewnętrznych obiektów, robisz już "hackowskie" OO. Ukrywanie prywatnych metod za pomocą odwołań CODE wydaje się pasować do tego całkiem dobrze. –

+0

@Michael w rzeczywistości, gdy już przyzwyczaisz się do każdego atrybutu jako funkcji haszującej obiekty zewnętrze, staje się to całkiem naturalne! – ennuikiller

1

Tak jak ja sobie z tym jest dodać coś takiego na początku metody:

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

Nie jest to w żadnym wypadku prawdziwa enkapsulacja, ale oznacza to, że osoba dzwoniąca za pośrednictwem pakietu będzie musiała przekazać instancję obiektu jako pierwszy argument. Ogólnie rzecz biorąc, w przypadku Perla, nie ma sensu chronić się przed złośliwymi użytkownikami mojego API - pomaga mi to po prostu uchwycić sytuacje, w których przypadkowo próbuję wywołać metodę jako metodę klasy (która zdarza się częściej niż chciałbym przyznać).

Osobiście uważam, że konwencja podkreślenia + wyraźne udokumentowanie metody jako prywatnej (lub jej nieudokumentowanie, aby nie pojawiała się w POD) jest wystarczająca do użytku w świecie rzeczywistym. Tak też działa w Pythonie. Jest to część language philosophy, która nie ogranicza użytkowników.

moduł

Perl woleliby, aby trzymać się z jego pokoju, bo nie zostali zaproszeni, a nie dlatego, że ma strzelbę ...

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

Właśnie odkryłem ten wzór w książce "Camel" niedawno po wielu latach programowania Perla, Jestem zaskoczony, że nie jest więcej używana. Ale myślę, że wszystkie odpowiedzi dotyczące tego, co stało się normą w odpowiedzi społeczności, że. ;-) – drnewman

Powiązane problemy