Uzyskaj dostęp do prywatnego pola innego obiektu w tej samej klasie

91
class Person 
{
   private BankAccount account;

   Person(BankAccount account)
   {
      this.account = account;
   }

   public Person someMethod(Person person)
   {
     //Why accessing private field is possible?

     BankAccount a = person.account;
   }
}

Proszę zapomnij o projekcie. Wiem, że OOP określa, że ​​obiekty prywatne są prywatne dla klasy. Moje pytanie brzmi: dlaczego OOP został zaprojektowany w taki sposób, że pola prywatne mają dostęp na poziomie klasy, a nie na poziomie obiektu ?

Nageswaran
źródło
5
Uważam, że OP traktuje obiekt "Person" przekazany do "someMethod" jako oddzielny obiekt, a zatem metoda nie powinna mieć dostępu do swoich prywatnych członków ... nawet jeśli znajduje się w klasie "Person".
Inisheer
1
Niektóre języki tego nie robią (na przykład nowomowa). Prawdopodobnie nie uzyskasz dobrej odpowiedzi, dlaczego. Otrzymasz odpowiedzi działające wstecz od tego, co zostało określone.
Tom Hawtin - tackline
Nie someMethodjest ważny. Nic nie zwraca. To musi być void.
Nicolas Barbulesco
1
Gdyby tak nie było, byłoby bardzo trudno napisać konstruktora kopiującego i operatora przypisania imo.
rozina

Odpowiedzi:

69

Jestem też trochę ciekawa odpowiedzi.

Najbardziej satysfakcjonującą odpowiedzią, jaką znalazłem, jest Artemix w innym poście tutaj (zmieniam nazwę AClass na klasę Person): Dlaczego mają modyfikatory dostępu na poziomie klasy zamiast na poziomie obiektu?

Prywatny modyfikator wymusza zasadę hermetyzacji.

Chodzi o to, że „świat zewnętrzny” nie powinien wprowadzać zmian w wewnętrznych procesach Person, ponieważ implementacja Person może zmieniać się w czasie (i musiałbyś zmienić cały świat zewnętrzny, aby naprawić różnice w implementacji - co jest prawie niemożliwe).

Kiedy instancja Person uzyskuje dostęp do wewnętrznych elementów innej instancji Person - możesz mieć pewność, że obie instancje zawsze znają szczegóły implementacji klasy Person. Jeśli logika procesów wewnętrznych w Person ulegnie zmianie - wystarczy zmienić kod Person.

EDYCJA: Prosimy o głosowanie na odpowiedź Artemixa. Po prostu go kopiuję i wklejam.

Iwan Satria
źródło
4
To jest prawdopodobnie powód. Ale to zły pomysł . To zachęca do złych praktyk. Programista uzyskujący dostęp do pola Personw klasie Personnie musi znać implementacji całej klasy. Dobrą praktyką jest użycie akcesorium bez konieczności znajomości operacji wykonywanych przez akcesorium.
Nicolas Barbulesco
16
@NicolasBarbulesco Myślę, że powód podany w odpowiedzi jest rozsądny. Załóżmy na przykład, że chcesz zaimplementować equals(Object)metodę w klasie Java, aby sprawdzić równość Personobiektu z inną instancją Person. Możesz chcieć umożliwić światu zewnętrznemu sprawdzanie, czy dwa wystąpienia są równe, ale możesz nie chcieć ujawniać wszystkich prywatnych pól klasy niezbędnych do sprawdzania równości światu zewnętrznemu za pomocą publicznych metod dostępu. Posiadanie dostępu do privatepól na poziomie klasy umożliwia implementację takiej metody bez wymuszonej konieczności implementacji takich metod publicznych.
Malte Skoruppa
1
@MalteSkoruppa - To jest dobry przykład (implementacja metody equals).
Nicolas Barbulesco
@MalteSkoruppa - Jednak implementację metody equalsmożna wykonać, wywołując prywatne metody dostępu .
Nicolas Barbulesco
@NicolasBarbulesco Tak, oczywiście, ale chodzi o to, czy używasz prywatnych akcesorów, czy bezpośrednio uzyskujesz dostęp do prywatnych pól do implementacji metody, privatemusi przyznać dostęp na poziomie klasy. Zgadzam się, że używanie akcesoriów jest ogólnie dobrym nawykiem, chociaż w tym przypadku jest to głównie kwestia kontekstu i osobistego stylu. Zwróć uwagę, że zarówno Joshua Bloch w efektywnej Javie (punkt 8), jak i Tal Cohen w tym artykule dr. Dobbsa mają bezpośredni dostęp do pól prywatnych w swoich listach kodu podczas omawiania sposobu implementacji equals.
Malte Skoruppa
17

Zobacz specyfikację języka Java, Rozdział 6.6.1. Określanie dostępności

W Stanach

W przeciwnym razie, jeśli zostanie zadeklarowany element członkowski lub konstruktor private, dostęp jest dozwolony wtedy i tylko wtedy, gdy występuje w treści klasy najwyższego poziomu (§7.6), która zawiera deklarację elementu członkowskiego lub konstruktora.

Kliknij powyższy link, aby uzyskać więcej informacji. Odpowiedź brzmi więc: ponieważ James Gosling i inni autorzy Javy zdecydowali, że tak będzie.

jlordo
źródło
17

Dobre pytanie. Wydaje się, że modyfikator dostępu na poziomie obiektu jeszcze bardziej wymusiłby zasadę enkapsulacji.

Ale w rzeczywistości jest odwrotnie. Weźmy przykład. Załóżmy, że chcesz głęboko skopiować obiekt w konstruktorze, jeśli nie możesz uzyskać dostępu do prywatnych członków tego obiektu. Wtedy jedynym możliwym sposobem jest dodanie publicznych akcesorów do wszystkich członków prywatnych. W ten sposób obiekty będą widoczne dla wszystkich innych części systemu.

Zatem hermetyzacja nie oznacza zamknięcia się na całą resztę świata. Oznacza to wybiórcze podejście do tego, na kogo chcesz być otwarty.

Wei Qiu
źródło
2
Ta odpowiedź wymaga głosowania! Inne odpowiedzi po prostu ponownie określają „regułę”, ale tylko ta naprawdę ujawnia przyczynę reguły i trafia w sedno.
mzoz
4
Ale czy nie byłoby lepiej, gdyby obiekt był odpowiedzialny za dostarczanie kopii samego siebie? Następnie, jeśli potrzebujesz głębokiej kopii obiektu, nie ma znaczenia, czy jesteś innym obiektem tej samej klasy, czy obiektem innej klasy: to ten sam mechanizm o.deepCopy()lub cokolwiek innego.
dirtside
4

To działa, ponieważ jesteś w class Personklasie - może zaglądać do własnego typu klasy. To naprawdę pomaga, gdy chcesz napisać konstruktor kopiujący, na przykład:

class A
{
   private:
      int x;
      int y;
   public:
      A(int a, int b) x(a), y(b) {}
      A(A a) { x = a.x; y = y.x; }
};

Lub jeśli chcemy pisać operator+i operator-dla naszej dużej klasy liczbowej.

Mats Petersson
źródło
Jest to coś podobnego do wstrzykiwania zależności. W którym możesz również wstrzyknąć obiekt innej klasy, gdzie nie masz dostępu do zmiennej prywatnej.
Nageswaran
Jasne, jeśli próbujesz zbudować klasę A z obiektu klasy B, a B ma komponent prywatny, to albo A musi zostać uznany za przyjaciela, albo może widzieć tylko części publiczne [prawdopodobnie chronione, jeśli A pochodzi z B ].
Mats Petersson
W Javie i .net nie ma pojęcia znajomego. W takich przypadkach, jak sobie z tym poradzić?
Nageswaran
1

Tylko moje 2 centy na pytanie, dlaczego semantyka prywatnej widoczności w Javie jest na poziomie klasy, a nie na poziomie obiektu.

Powiedziałbym, że wygoda wydaje się tutaj kluczowa. W rzeczywistości prywatna widoczność na poziomie obiektu zmuszałaby do ujawnienia metod innym klasom (np. W tym samym pakiecie) w scenariuszu przedstawionym w PO.

Prawdę mówiąc, nie byłem w stanie ani wymyślić, ani znaleźć przykładu pokazującego, że widoczność na poziomie prywatnej klasy (jak oferowana przez Javę) stwarza jakiekolwiek problemy w porównaniu z widocznością na poziomie prywatnym obiektu.

To powiedziawszy, języki programowania z bardziej szczegółowym systemem polityk widoczności mogą zapewnić widoczność obiektów na poziomie obiektu i na poziomie klasy.

Na przykład Eiffel oferuje selektywny eksport: możesz wyeksportować dowolny obiekt klasowy do dowolnej wybranej klasy, od {NONE} (obiekt-prywatny) do {DOWOLNY} (odpowiednik publicznego, a także domyślnego), do {PERSON} (klasa prywatna, zobacz przykład OP), do określonych grup klas {PERSON, BANK}.

Warto również zauważyć, że w Eiffel nie trzeba ustawiać atrybutu jako prywatnego i pisać metody pobierającej, aby uniemożliwić innym klasom przypisywanie do niego. Atrybuty publiczne w Eiffel są domyślnie dostępne w trybie tylko do odczytu, więc nie potrzebujesz funkcji pobierającej tylko do zwrócenia ich wartości.

Oczywiście nadal potrzebujesz ustawiacza, aby ustawić atrybut, ale możesz go ukryć, definiując go jako „przypisującego” dla tego atrybutu. Pozwala to, jeśli chcesz, na użycie wygodniejszego operatora przypisania zamiast wywołania ustawiającego.

Temp Agilist
źródło
0

Ponieważ private modyfikator dostępu sprawia, że ​​jest widoczny tylko w klasie . Ta metoda jest nadal W klasie .

darijan
źródło
Moje pytanie brzmi: dlaczego jest zaprojektowany „w klasie”, ale dlaczego nie „tylko w obiekcie”?
Nageswaran
Ponieważ tak powstaje Java.
darijan
I dlaczego java zrobiła java w ten sposób?
Nageswaran,
Java tego nie zrobiła, jej twórcy. Czemu? Ponieważ rządzą!
darijan,
1
Twórcy Javy nie zrobią tego bez powodu i musi być jakiś powód, aby to robić; Pytam o powód
Nageswaran
0

privatepole jest dostępny w klasie / obiektu, w którym pole jest zadeklarowane. Jest prywatny dla innych klas / obiektów poza tą, w której się znajduje.

ola
źródło
-1

Pierwszą rzeczą, którą musimy zrozumieć, jest to, że wszystko, co musimy zrobić, to przestrzegać zasad Ups, więc hermetyzacja polega na zawinięciu danych w pakiet (tj. Klasie), a następnie przedstawieniu wszystkich danych jako obiektu i łatwego dostępu. więc jeśli ustawimy pole jako nieprywatne, to dostęp do niego jest indywidualny. i to prowadzi do złego paratytu.

Sachin Jadhav
źródło