W jaki sposób ewolucja OOP obejmowała pojęcie właściwości

12

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.

jxramos
źródło
8
Funkcja „goły język” jest po prostu wygodnym cukrem syntaktycznym dla metod pobierających i ustawiających. Czy istnieją głębsze powody interpretacji i terminologii, nie wiem.
W rundzie ekspertów OO tytuł pytania może prowokować i odwracać uwagę od tego, o co tak naprawdę pytałeś. Nie dlatego, że jestem ekspertem od OO, jestem tylko „użytkownikiem OO” od kilku lat.
Doc Brown
Jest to składniowa subtelność, za którą tęsknię, przechodząc od „metod bez parametrów” w Pythonie do C ++. BMI = bob.weight/sq(bob.height)ładniej czyta bez ()IMO.
OJFord
Myślę, że właściwości były w oryginalnym (nie .net) Visual Basic, jako sposób na skonfigurowanie obiektu Active X (COM). Siatka właściwości w tym narzędziu prawdopodobnie miała coś wspólnego z przyjęciem właściwości w językach. Zauważ, że oryginalny Visual Basic nie był zorientowany obiektowo na wiele sposobów, ale mógł tworzyć coś w rodzaju klas.
Frank Hileman,
Kontynuacja: okno właściwości było sposobem na konfigurację obiektów bez pisania kodu. Nazywano to rozwojem RAD. Ten link zawiera zrzut ekranu okna właściwości VB6: microsoft.com/mspress/books/WW/sampchap/4068.aspx
Frank Hileman

Odpowiedzi:

5

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)

    • mniej radykalna forma powyższego: pozbyć się danych w interfejsie publicznym , tzn. uczynić dane zawsze prywatnymi, w interfejsie publicznym ujawniać tylko metody (Smalltalk, Ruby to zrobić)
  • pozbyć się metod, po prostu mieć dane (Self robi to, „metody” to tylko Methodobiekty 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 metody foo_=, 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ć (lub abstract valzaimplementować) w podklasie za pomocą metody def foo)

Jednak Java nie przestrzega zasady jednolitego dostępu. W Javie można odróżnić dostęp do danych od uruchomienia metody. foo.barróżni się od foo.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.

Jörg W Mittag
źródło
1
Dlaczego (jak i inni) uważasz, że utrzymanie jednolitego dostępu jest tak ważne? W metodzie możesz chcieć nadać jej parametry, aby zmienić to, co robi lub działa. W przypadku pola lub właściwości nie masz tej możliwości, zwykle po prostu zwracasz dane (chociaż właściwość można zaimplementować jako uruchamiającą metodę zamiast po prostu ujawniającą prywatne pole). Wydaje mi się to intuicyjne, być może dlatego, że jestem do tego przyzwyczajony, ale co zyskałbyś na elegancji lub wydajności dzięki wymuszeniu jednolitego dostępu? Czy boisz się, że wyciekają szczegóły implementacji poza klasą?
Mike wspiera Monikę
1
UAP polega na zarezerwowaniu swobody zmiany szczegółów implementacji bez przerywania publicznego interfejsu. Typowym przykładem jest dodawanie rejestrowania. Jeśli oferuję dostęp za pośrednictwem metody, mogę w trywialny sposób zmienić elementy wewnętrzne metody, aby zapisać w dzienniku. W polu publicznym nie mogę dodać rejestrowania bez uprzedniego przekształcenia go w metodę, która psuje cały kod klienta. Jeśli nie można ryzykować zerwania zmian, koniecznością jest zastosowanie metod. Właściwości są optymalnym kompromisem, ponieważ są pełnymi metodami, ale wyglądają jak pola. Przestrzeganie UAP poprawia enkapsulację i zmniejsza szczelność połączenia.
amon
Wiele dobrych odpowiedzi na to pytanie, ale myślę, że to uderzyło w głowę, wyciągając bardziej podstawowe aspekty natury języków programowania i omawiając odpowiednią formalną koncepcję UAP. Solid
jxramos
18

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ę.

Doktor Brown
źródło
Nie ma to nic wspólnego z programowaniem obiektowym, z wyjątkiem tego, że właściwość jest abstrakcją pola, a pola są częścią programowania obiektowego. Ale jak słusznie zauważysz, właściwości nie są potrzebne do programowania obiektowego.
Frank Hileman,
2
@FrankHileman: „właściwość jest abstrakcją pola, a pola są częścią programowania obiektowego” - cóż, wydaje mi się, że zgadzasz się, że koncepcja ma przynajmniej coś wspólnego z OOP. I dlatego mnie przegłosowałeś?
Doc Brown
3
lol. Czy możesz go winić? Zsunął się z toalety i uderzył głową w zlew. W każdym razie ... Zawsze widziałem, że właściwości nie są ściśle związane z OO. Pomagają w enkapsulacji, a enkapsulacja pomaga w OO.
MetaFight,
1
Ha! To dla mnie całkiem wprowadzenie do programisty.stackexchange. Lol, o wiele gorętszy niż moje ekwiwalentne doświadczenie w zwykłym przepełnieniu stosu :-p Dobry sposób na zmieszanie dnia!
jxramos
11

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 GetXi SetXparowania 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.

Telastyn
źródło
7
Głosowałem za wami za zbyt wiele odniesień do nieistotnych formalnych bzdur. Rzeczywiste implementacje języków programowania mają znacznie poważniejsze rzeczy do rozważenia niż to, czy ich model został uwzględniony w rachunku lambda.
DeadMG,
9
@DeadMG - to z pewnością prawda, ale z drugiej strony realizatorzy języka programowania niezmiennie będą zaznajomieni z tą nieistotną formalną bzdurą . Myślenie, że nie miało to wpływu na ich projekty, jest naiwne.
Telastyn
3
To zdecydowanie nie jest „nieistotne bzdury formalne”. Jednak rachunek lambda mógł nie być brany pod uwagę w przypadku wczesnych języków programowania. Jeśli tak, procesory prawdopodobnie byłyby bardziej zorientowane na tę mentalność.
Frank Hileman
3
@FrankHileman - Jestem prawie pewien, że Lisp zastanawiał się nad tym ...
Telastyn
4
@Telastyn - tak - a Lisp pierwotnie nie miał być językiem programowania, pamiętasz?
Frank Hileman
3

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.

niwax
źródło
Nie sądzę, że powinieneś zignorować pochodzenie C #, które pochodziło z Delphi, a wcześniej Object Object i Turbo Pascal z Objects. Były zorientowane obiektowo i miały właściwości (choć nie pamiętam, czy OP miało właściwości z TP 5.5, czy też zostały dodane; przypuszczalnie były kontynuowane w C # przez Andersa, ponieważ były pragmatycznie dobrym pomysłem.
amaca
Bardzo interesujące, że zdarzyło ci się być jedynym, który trafił na aspekt tego pytania. Właśnie dodałem komentarz do mojego pytania prowadzącego do witryny, która zawiera listę właściwości jako część modelu właściwości zdarzenia-metody, który spełnia C #. Następnie ponownie przeszukałem stronę mojego pytania, szukając „komponentu”, w którym znalazło się kilka fałszywych wyników pozytywnych, ale myślę, że twoja odpowiedź rzeczywiście pokrywa się z tym, z czym się łączyłem.
jxramos
3

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:

  • W metodzie zestawu właściwości, przed zapisaniem wartości właściwości, nowa wartość lub stan obiektu może być sprawdzony pod kątem zestawu warunków wstępnych lub niezmienników.
  • Metoda pobierania właściwości może istnieć dla wygody, jeśli odzyskanie wartości właściwości można logicznie uznać za równoważne z odzyskaniem wartości pola.
  • Metoda zestawu właściwości może wykonywać inne operacje, takie jak powiadamianie obiektu nadrzędnego lub nasłuchiwanie obiektów o zmianie wartości właściwości.

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.

Frank Hileman
źródło
2
Pierwsza linia z artykułu z Wikipedii. „Właściwość, w niektórych obiektowych językach programowania, jest szczególnym rodzajem członka klasy ...”. Twoje pierwsze zdanie jest więc błędne. Pozostała część nie odpowiada na pytanie.
Doc Brown
1
@DocBrown: Ciekawa odpowiedź. Wiele artykułów z Wikipedii jest wyraźnie niepoprawnych. Zakładam, że bronisz autora tego konkretnego artykułu?
Frank Hileman,
1
Nie wszystkie funkcje obiektowych języków programowania są powiązane z pojęciami zorientowanymi obiektowo.
Frank Hileman,
1
To nie zmienia faktu, że nie odpowiadasz na pytanie.
Doc Brown
3
Należy zauważyć, że nie tylko seter jest opcjonalny. Możesz mieć tylko właściwości ustawiające.
Telastyn
2

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ć.

Stan Rogers
źródło
Zgadzam się z niektórymi punktami i nie zgadzam się z innymi, ale ogólna wiadomość jest dobra: niektóre informacje o obiekcie muszą zostać obliczone, ale nadal są technicznie informacjami, które raczej działaniem, niż można je wykonać .
Pharap
0

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.

DeadMG
źródło
3
Czy kiedykolwiek widziałeś koncepcję własności w jakimkolwiek języku programowania poza kontekstem klasy lub obiektu? Nie mam.
Doc Brown
1
@DocBrown: Zaimplementowałem to. Faktem jest, że właściwości są dość mało wartościowymi celami dla autorów języków, ponieważ ich poprawa w stosunku do zwykłych wywołań funkcji jest niska.
DeadMG,
1
OP pyta o historię właściwości jako koncepcji w popularnych językach programowania. W rzeczywistości w sensie historycznym istnieje związek między właściwościami a OOP.
Doc Brown
2
Może trochę pochopnie przypisałem tę koncepcję właściwości paradygmatu OOP per se, ale jako koncepcja z pewnością wykracza poza poszczególne języki i ich cechy. Może staram się sformułować odpowiednią ontologię między nimi. Nie sugeruję w tytule pytania, że ​​właściwości są podstawową cechą / koncepcją OOP, która tworzy lub łamie formalizm OOP, a jednak wydaje mi się, że mają rzeczywistość tylko w tej przestrzeni OOP, dlatego sformułowałem pytanie jako takie .
jxramos
4
Nie są one tylko cukrem składniowym w języku C #, istnieją w metadanych zestawu jako odrębne elementy i możesz robić rzeczy z właściwościami, których nie możesz z polami, takimi jak wiązanie danych.
Andy,