Pochodzę ze środowiska C ++ i wychodzę z C # w mojej obecnej pracy i właśnie czytałem wiele pytań i odpowiedzi na temat różnicy między polami publicznymi i właściwościami a wszystkimi tam iz powrotem w odmianach i inkarnacjach tego podstawowe pytanie (np. ten post SO i wszystkie powiązane powiązane pytania ). Wszystkie te pytania są rozpatrywane pod względem praktycznych różnic, które przyjmują za pewnik istnienie systemu nieruchomości, ale myślę, że dobrze byłoby podejść do tego tematu w odniesieniu do tego, co projektanci wszystkich języków, którzy zdecydowali się wspierać właściwości w pierwszym myśleli o miejscu (sprawdź listę w artykule w Wikipedii tutaj). W jaki sposób OOP ewoluowało z C ++ / Java, aby rozszerzyć się na to, co artykuł Wikipedii interesująco identyfikuje jako środek między metodami a danymi członka:
„Oznacza to, że właściwości są pośrednie między kodem elementu (metody) a danymi elementu (zmienne instancji) klasy, a właściwości zapewniają wyższy poziom enkapsulacji niż pola publiczne”.
MSDN dodaje kolejne tło:
„Chociaż właściwości są technicznie bardzo podobne do metod, różnią się one pod względem scenariuszy użycia. Powinny być postrzegane jako inteligentne pola. Mają składnię wywoływania pól i elastyczność metod”.
Chciałbym wiedzieć, w jaki sposób doszło do tego, że ten pośredni poziom enkapsulacji okazał się przydatny do programowania w ogóle. Zakładam, że ta koncepcja nie była obecna przy pierwszym wcieleniu języków programowania, które wyrażały paradygmat OOP.
BMI = bob.weight/sq(bob.height)
ładniej czyta bez()
IMO.Odpowiedzi:
Chodzi przede wszystkim o enkapsulację i zasadę jednolitego dostępu.
Obiekt powinien być w stanie odpowiedzieć na wiadomość, zwracając istniejące dane lub uruchamiając metodę, ale nadawca nie powinien być w stanie stwierdzić, który jest który. Lub jeśli przeglądasz to od strony nadawcy: nadawca powinien mieć dostęp do istniejących danych lub uruchomić metodę poprzez jednolity interfejs.
Można to osiągnąć na kilka sposobów:
pozbywaj się danych całkowicie, po prostu zastosuj metody (Newspeak to robi)
pozbyć się metod, po prostu mieć dane (Self robi to, „metody” to tylko
Method
obiekty przypisane do zmiennych instancji, zmienne instancji są wyszukiwane za pomocą wirtualnej wysyłki)nie wprowadzaj rozróżnienia składniowego ani semantycznego między metodami a danymi (robi to Scala, dostęp do pola jest syntaktycznie nie do odróżnienia od wywołania metody bez listy argumentów (
foo.bar
), przypisanie do pola jest syntaktycznie nierozróżnialne od wywołania specjalnie nazwanej metody (foo.bar = baz
) jest to samo ponieważfoo.bar_=(baz)
np. wywołanie nazwanej metodyfoo_=
, a wartości tylko do odczytu można zastąpić lub zaimplementować za pomocą metody bez listy parametrów (tj.val foo
) w nadklasie można zastąpić (lubabstract
val
zaimplementować) w podklasie za pomocą metodydef foo
)Jednak Java nie przestrzega zasady jednolitego dostępu. W Javie można odróżnić dostęp do danych od uruchomienia metody.
foo.bar
różni się odfoo.bar()
. Powodem tego jest to, że pola i metody są semantycznie i składniowo odrębne.C # próbuje to naprawić, dodając właściwości do języka, w zasadzie metody wyglądające jak pola. Jednak wywołania metod nadal wyglądają inaczej niż w przypadku dostępu do pól i właściwości. Pola i właściwości mają teraz jednolity dostęp, ale metody nadal nie.
Więc to tak naprawdę nie rozwiązuje problemu: nie można naprawić dwóch różnych sposobów dostępu do rzeczy, dodając trzeci sposób dostępu do rzeczy! Nawet jeśli ten trzeci sposób wygląda jak jeden z dwóch pozostałych sposobów, nadal będziesz mieć (co najmniej) dwa różne sposoby. Możesz to naprawić tylko poprzez pozbycie się wszystkich różnych sposobów oprócz jednego lub pozbycie się różnic.
Język z metodami, właściwościami i polami jest w porządku, ale wszystkie trzy powinny mieć jednolity dostęp.
źródło
Cóż, nie jestem w 100% pewien, ale myślę, że rzeczy są prawdopodobnie prostsze niż się spodziewasz. W szkołach modelowania OO z lat 90-tych istniało zapotrzebowanie na modelowanie klas z enkapsulowanymi atrybutami składowymi, a po zaimplementowaniu w językach takich jak C ++ lub Java, zwykle prowadziło to do kodu z dużą liczbą pobierających i ustawiających, więc dużo „szumu” kod względnie prostego wymagania. Zauważ, że większość (prawdopodobnie wszystkie nie sprawdzały tego) języków wymienionych w linkowanym artykule w Wikipedii zaczęła wprowadzać „właściwości” obiektów pod koniec lat 90-tych lub później.
Wydaje mi się, że to był główny powód, dla którego projektanci języków postanowili dodać cukier syntaktyczny, aby zmniejszyć ten hałas. I chociaż właściwości z pewnością nie są „podstawową koncepcją OO”, to przynajmniej mają coś wspólnego z orientacją obiektową. Nie pokazują „ewolucji OOP” (jak zakłada tytuł pytania), ale obsługują modelowanie OO na poziomie języka programowania, aby ułatwić implementację.
źródło
Masz to do tyłu (w pewnym sensie). Lambda Calculus istnieje jako podstawowa formalna podstawa języków programowania i istnieje od dziesięcioleci. Nie ma pól.
Aby modelować stan zmienny, musisz wykonać dwie abstrakty. Jeden reprezentuje ustawienie jakiegoś stanu, a drugi, który pobiera ten stan (Rozdział 13 w mojej wersji TaPL w celach informacyjnych). Brzmi znajomo? Z teoretycznego tła OO nie ewoluowało, aby mieć takie rzeczy. OO przeczytał Języki programowania 101 i zrobił mały krok do przodu.
Z praktycznego punktu widzenia istnieją dwie dość jasne motywacje. Pochodzisz z języka C ++, więc co by się stało, gdybyś miał pole publiczne - powiedzmy ... tekst w polu tekstowym. Co dzieje się, gdy chcesz zmienić projekt, aby „za każdym razem, gdy zmienia się to pole tekstowe, bla”? Możesz zabić to pole, utworzyć funkcję lub dwa i uporządkować tę logikę, ponieważ nie możesz ufać programistom, że sami wywołają „UpdateTextbox”. Jest to bardzo przełomowa zmiana w interfejsie API (i niestety wciąż przełomowa zmiana w implementacji właściwości .NET). Tego rodzaju zachowanie jest wszędzie w interfejsie API Windows. Ponieważ jest to wielka sprawa w Microsoft, C # prawdopodobnie chciał uczynić to mniej bolesnym.
Inną dużą motywacją są Java Beans i ich krewni. Zbudowano wiele frameworków, które wykorzystują odbicie Java do wyszukiwania
GetX
iSetX
parowania oraz skutecznego traktowania ich jak nowoczesnych właściwości. Ponieważ jednak nie były to konstrukcje językowe, ramy te były kruche i niewygodne. Jeśli wpiszesz imię, wszystko po prostu się załamie. Jeśli ktoś został odnowiony, nic nie przeniosło się na drugą stronę nieruchomości. A robienie całego pola / get / set bojlerów było pełne i żmudne (nawet dla Javy!). Ponieważ C # został opracowany głównie jako „Java z nauczonymi lekcjami”, ten rodzaj bólu był jedną z tych lekcji.Ale najważniejsze jest to, że koncepcja nieruchomości okazała się sukcesem. Jest łatwy do zrozumienia, łatwy w użyciu. Pomagają one znacznie w adaptacji i jako narzędzie programiści odkryli, że właściwości rozwiązują podzbiór problemów w bardziej przejrzysty sposób niż funkcje lub pola.
źródło
W szczególności w .net właściwości pochodzą ze starych czasów Visual Basic, które, jak się zdarza, nie były zorientowane obiektowo w taki sposób, w jaki myślimy o tym dzisiaj. Zostało w dużej mierze zbudowane wokół nowego wówczas systemu COM, który powierzchownie traktował wszystko niekoniecznie jako klasy, ale pod względem komponentów, które ujawniałyby właściwości, do których można uzyskać dostęp zarówno w kodzie, jak i edytorach graficznych. Kiedy VB i nowo utworzone C # zostały połączone w .net, VB zyskał wiele funkcji OOP i zachował właściwości, ponieważ usunięcie ich byłoby jak krok wstecz - wyobraź sobie, że narzędzie do automatycznej aktualizacji kodu, które mieli w Visual Studio, było zamieniając wszystkie twoje właściwości na metody pobierające i ustawiające i łamał kompatybilność ze wszystkimi bibliotekami COM. Wspieranie ich byłoby logiczne.
źródło
Właściwości nie mają nic wspólnego z programowaniem obiektowym, ponieważ właściwości to tylko cukier składniowy. Właściwości wyglądają jak pola powierzchownie, aw świecie .net zaleca się, aby zachowywały się jak pola pod pewnymi względami, ale w żadnym sensie nie są polami. Właściwości to cukier składniowy dla jednej lub dwóch metod: jednej, aby uzyskać wartość, a drugiej, aby ustawić wartość. Można ustawić metodę set lub get, ale nie jedno i drugie. Może nie być pola przechowującego wartość zwróconą przez metodę get. Ponieważ dzielą składnię z polami i ponieważ często używają pól, ludzie kojarzą właściwości z polami.
Właściwości mają zalety w stosunku do pól:
Ponieważ właściwości są abstrakcją pól, a dla wygody składniowej języki, takie jak C #, przyjęły składnię pól dla właściwości.
źródło
Jest to kwestia implementacji kontra implikacji . Właściwości były w OOP, zanim C ++ lub Java pojawiły się na scenie (były tam, z pewną szorstkością wokół krawędzi, w Simula i są fundamentalne dla Smalltalk). Elementy z właściwościami różnią się koncepcyjnie od wartości z dołączonym kodem. Prefiksy get & set w niektórych konwencjach językowych służą jedynie do mętnienia wód; uświadamiają ci różnicę między polami i właściwościami, zakładając, że do pól można uzyskać bezpośredni dostęp bez pobierania / ustawiania w sposób idiomatyczny dla języka i to jest nieszczelne.
Cały sens OOP polega na traktowaniu rzeczy tak, jakby były bytami w „prawdziwym” świecie, a nie tylko strukturami z pomieszanym kodem. Inny programista powinien wiedzieć bardzo, bardzo mało o tym, jak zaimplementowałem rzeczy, i nie powinny w ogóle martwić się, które z różnych wartości, które mogą otrzymać i / lub ustawić, są prawdziwe, a które wirtualne. Jeśli natkniesz się na mój wektor, nie powinieneś wiedzieć, czy przechowuję kąt i wielkość, czy rzeczywiste i urojone komponenty wewnątrz obiektu wektorowego. Jeśli zmienię reprezentację w wersji 2.0 mojej biblioteki, nie powinno to w ogóle wpływać na twój kod (choć możesz chcieć skorzystać z nowych, fajnych funkcji). Podobnie istnieją właściwości, które jednostka może mieć, które zależą od danych zewnętrznych w stosunku do jednostki, ale które są niewątpliwie właściwościami z leksykalnego punktu widzenia. Pytasz ludzi „ile masz lat”, a nie „proszę wykonać obliczenia, które ujawnią mi twój wiek”, nawet jeśli wiesz, że dane dostępne dla tego „obiektu” to data urodzenia (prywatny niezmienny członek) i dzisiejsza data (publiczna, automatycznie zwiększająca wartość własność środowiska, zależna od strefy czasowej, czasu letniego i Międzynarodowej Linii Danych). Wiek jest właściwością, a nie metodą, chociaż dotarcie do niego wymaga pewnych obliczeń i nie może (z wyjątkiem komputerowych zabawek przedstawień rzeczy o sztucznie ograniczonym czasie życia) być przechowywany jako pole. nawet jeśli wiesz, że dane dostępne dla tego „obiektu” to data urodzenia (prywatny niezmienny członek) i dzisiejsza data (publiczna, automatycznie zwiększająca się właściwość środowiskowa, zależna od strefy czasowej, czasu letniego i międzynarodowej linii dat) ). Wiek jest właściwością, a nie metodą, chociaż dotarcie do niego wymaga pewnych obliczeń i nie może (z wyjątkiem komputerowych zabawek przedstawień rzeczy o sztucznie ograniczonym czasie życia) być przechowywany jako pole. nawet jeśli wiesz, że dane dostępne dla tego „obiektu” to data urodzenia (prywatny niezmienny członek) i dzisiejsza data (publiczna, automatycznie zwiększająca się właściwość środowiskowa, zależna od strefy czasowej, czasu letniego i międzynarodowej linii dat ). Wiek jest właściwością, a nie metodą, chociaż dotarcie do niego wymaga pewnych obliczeń i nie może (z wyjątkiem komputerowych zabawek przedstawień rzeczy o sztucznie ograniczonym czasie życia) być przechowywany jako pole.
Zamiast myśleć o właściwościach jako draniu dzieci pól i metod, o wiele bardziej satysfakcjonuje to, że metody są wyspecjalizowanym rodzajem własności - rzeczy, które twoje istoty mogą zrobić, a nie rzeczy, którymi są. W przeciwnym razie nie zajmujesz się obiektami / obiektami koncepcyjnie, masz do czynienia z kolekcjami danych, do których dołączono kod. W implementaions mogą być identyczne, ale konsekwencje są różne.
Nie trzeba jednak mówić, że ta abstrakcja wiąże się z pewnymi kosztami. Jeśli programista korzystający z klasy nie jest w stanie stwierdzić, czy uzyskuje dostęp do danych w trakcie ich przechowywania, czy też pobiera / ustawia wartości, które należy obliczyć, wówczas poziom, na którym język jest koniecznie niepewny (i dlatego może wymagają, aby wszystko wymagało kodu pośredniczącego między akcesoriami / selektorami a wartościami). Nie ma nic koncepcyjnie złego w „strukturach z kodem” - z pewnością mogą być znacznie wydajniejsze - ale przeciekają implementację wszędzie, i to jest jedna z rzeczy, które OOP ma wyeliminować.
źródło
Absolutnie nic. Właściwości i OOP nie mają ze sobą nic wspólnego. Właściwości są niczym więcej niż cukrem syntaktycznym dla wywołań funkcji, a zatem mają dokładnie to samo załączenie OOP, które wywołuje funkcja - co oznacza brak.
Nawiasem mówiąc, Wikipedia jest całkowicie niepoprawna. Wzorzec getMember / setMember, który widzisz w Javie, oferuje dokładnie takie same zalety (i wady) jak właściwości w języku C #. Możesz powtórzyć ten wzór nawet w C, jeśli chcesz.
Właściwości w języku C # są niczym więcej niż obsługiwanym językiem cukrem syntaktycznym.
źródło