Jaki jest sens właściwości?

11

Oto kilka argumentów dla właściwości i moich kontrargumentów:

Łatwiejszy w użyciu niż pisanie metod pobierających i ustawiających

Pary metod Gettera i Settera są zapachem kodu. Ułatwienie ich pisania jest jak ułatwienie zaliczenia testu matematycznego za pomocą formularza Scantron i wypełnienia wszystkich liter „C”. Obiekty, które zawierają tylko stan, dla trwałości, nie powinny używać pobierających / ustawiających i powinny tworzyć niezmienne obiekty w czasie trwałości.

Dla konsumenta przedmiotu ważne jest to, co robi, a nie jak to robi. Zachowuje się tak, jak robi; jego stan jest taki, jak to robi. Jeśli czujesz, że dbasz o stan obiektu (z wyjątkiem uporczywości, chociaż to również łamie OO), po prostu nie robisz OOP i nie tracisz jego zalet.

Dają przybliżone wyniki konsumentom

To może się zmienić w przyszłości dla dowolnej nieruchomości. Załóżmy, że w wersji 1.0 uzyskanie dostępu do PropertyX po prostu zwraca pole. W wersji 1.5, jeśli pole ma wartość null, PropertyX używa wzorca Null Object do utworzenia nowego obiektu null. W wersji 2.0 pole jest dalej sprawdzane za pomocą metody pobierającej w PropertyX.

Ponieważ właściwość staje się coraz bardziej złożona, wskazanie wydajności korzystania z właściwości wydaje się coraz mniej prawdziwe.

Są lepsze niż pola publiczne

To prawda. Ale są też metody.

Reprezentują zasadniczo inny aspekt obiektu niż metody i wszyscy konsumenci obiektu powinni o to dbać

Czy jesteś pewien, że oba powyższe stwierdzenia są prawdziwe?

Łatwiej je pisać, stary

Jasne, pisanie myObject.Lengthjest łatwiejsze niż pisanie myObject.Length(), ale czy nie można tego naprawić odrobiną cukru syntaktycznego?


Dlaczego warto korzystać z metod zamiast właściwości?

  • Brak gwarancji wydajności. Interfejs API pozostanie zgodny z prawdą, nawet jeśli metoda stanie się bardziej złożona. Konsument będzie musiał profilować swój kod, jeśli napotyka problemy z wydajnością, a nie opierać się na słowie API.

  • Mniej do myślenia przez konsumenta. Czy ta właściwość ma funkcję ustawiającą? Metoda na pewno nie.

  • Konsument myśli z właściwego sposobu myślenia OOP. Jako konsument interfejsu API jestem zainteresowany interakcją z zachowaniem obiektu. Kiedy widzę właściwości w interfejsie API, wygląda bardzo podobnie do stanu. W rzeczywistości, jeśli właściwości robią za dużo, nie powinny nawet być właściwościami, więc tak naprawdę właściwości w stanie API ARE są takie, jakie wyglądają dla konsumentów.

  • Programista API głębiej zastanowi się nad metodami ze zwracanymi wartościami i, jeśli to możliwe, uniknie modyfikowania stanu obiektu w takich metodach. W miarę możliwości należy egzekwować oddzielanie poleceń od zapytań.


Pytam więc, dlaczego warto używać właściwości zamiast metod? Większość punktów w MSDN to same w sobie zapachy kodowe i nie należą one ani do właściwości, ani do metod.

(Te myśli przyszły mi do głowy po myśleniu o CQS.)

Xofz
źródło
5
+1. Właściwości to metody ze składnią pól i to po prostu nie ma sensu.
Nemanja Trifunovic
23
@Nemanja Trifunovic: To ma sens, jeśli napisałeś type GetFoo() void SetFoo()dziesięć tysięcy razy. Przez cały czas pisania kodu C # nigdy nie byłem zdezorientowany przez właściwość.
Ed S.
23
Brzmi dla mnie tak, jakbyś już podjął decyzję. Jakie jest pytanie?
Dean Harding
9
@Nemanja Trifunovic: „Gettery i setery są ogólnie złe” Możesz to powtarzać tyle razy, ile chcesz, ale to nie pomoże. Co powiesz na wyjaśnienie, dlaczego uważasz, że są złe? O ile SO ulega awarii z powodu wpisania nazwy właściwości zamiast podstawowej nazwy zmiennej, nie można pominąć błędu, ponieważ spowoduje to awarię programu, gdy tylko wywołasz właściwość, i jest to dość rzadkie. Kiedy to się dzieje, wiem dokładnie, co zrobiłem, aby to spowodować, i mam to naprawić w ciągu dwóch sekund. Nie widzę problemu.
Ed S.
3
Przechodząc tylko, aby wskazać @NemanjaTrifunovic, że to, dlaczego metody pobierające i ustawiające są złymi artykułami, jest dość stare , dotyczy javy i podkreśla słabość javy : słabość braku właściwości . (stąd popisywanie się zbyt wieloma szczegółami implementacji)… gryząc nas tutaj. (powinno być zatytułowane „ getters” i „setery” są złe w java, ponieważ nie mamy cholernie dobrze przemyślanego standardu na ich temat )
ZJR

Odpowiedzi:

44

Dlaczego są to „metody przeciw właściwościom”? Metoda coś robi. Właściwość jest, no cóż, członkiem obiektu. Są to zupełnie różne rzeczy, chociaż dwa rodzaje powszechnie pisanych metod - pobierające i ustawiające - odpowiadają właściwościom. Ponieważ porównywanie właściwości z metodami w ogóle nie ma znaczenia, zakładam, że chciałeś porozmawiać o getterach / setterach.

Pary metod Gettera i Settera są zapachem kodu.

Niekoniecznie, argumentowałbym, ale w każdym razie nie jest to kwestia getters / setters vs. właściwości, ale kwestia, czy należy użyć któregoś z nich. Pamiętaj również, że możesz np. Pominąć setXczęść, tak jak możesz tworzyć właściwości tylko do odczytu.

Dla konsumenta przedmiotu ważne jest to, co robi, a nie jak to robi. Zachowuje się tak, jak robi; jego stan jest taki, jak to robi. Jeśli czujesz, że dbasz o stan obiektu (z wyjątkiem uporczywości, chociaż to również łamie OO), po prostu nie robisz OOP i nie tracisz jego zalet.

Bardzo wątpliwe podejście. Jeśli GUI chce wyprowadzać dane przechowywane przez a DataStuffManagerImpl, musi jakoś pobrać z niego tę liczbę (i nie, wrzucenie połowy aplikacji do klasy widżetu nie jest opcją).

Ponieważ właściwość staje się coraz bardziej złożona, wskazanie wydajności korzystania z właściwości wydaje się coraz mniej prawdziwe.

[Metody mają] Brak gwarancji wydajności. Interfejs API pozostanie zgodny z prawdą, nawet jeśli metoda stanie się bardziej złożona. Konsument będzie musiał profilować swój kod, jeśli napotyka problemy z wydajnością, a nie opierać się na słowie API.

W prawie wszystkich przypadkach cała logika walidacji itp. Jest nadal efektywnie O (1) lub w inny sposób nieznaczna pod względem kosztów. Jeśli nie, być może posunąłeś się za daleko i nadszedł czas na zmianę. I getX()metoda jest zwykle traktowana jako tania!

Jasne, wpisanie myObject.Length jest łatwiejsze niż wpisanie myObject.Length (), ale czy nie można tego naprawić za pomocą odrobiny cukru syntaktycznego?

Właściwości to cukier syntaktyczny.

Mniej do myślenia przez konsumenta. Czy ta właściwość ma funkcję ustawiającą? Metoda na pewno nie.

„Czy istnieje setter dla tego gettera?” Ta sama różnica.

Programista API głębiej zastanowi się nad metodami ze zwracanymi wartościami i, jeśli to możliwe, uniknie modyfikowania stanu obiektu w takich metodach. W miarę możliwości należy egzekwować oddzielanie poleceń od zapytań.

Nie jestem pewien, co chcesz nam tutaj powiedzieć. W przypadku właściwości istnieje jeszcze silniejsze niepisane prawo, aby nie powodować skutków ubocznych.

ChrisF
źródło
3
+1, I to nie jest niepisane prawo. Wytyczne użytkowania MSDN zawierają wiele innych. Myślę, że OP powinien je przejrzeć, aby wyjaśnić wiele wątpliwości. Nie mogę opublikować tutaj linku, ponieważ piszę to z mojego telefonu, ale wskazówki powinny być łatwe do znalezienia.
decyklon
@delnan: Właściwości nie są tym cukrem syntaktycznym. Właściwości mogą być traktowane jak pola (mogą być użyte jako cel przypisania, jeśli mają one funkcję ustawiającą). Metody nie mogą.
xofz
1
@SamPearson: obj.x = ymapy do obj.setX(y)i obj.xmapy do obj.getX(). Czym to się różni?
1
@SamPearson możesz zmienić widoczność ustawiacza właściwości i gettera niezależnie od siebie. Używam tego cały czas z moimi obiektami Entity Framework: moje setery są chronione (więc tylko framework może ustawić wartość). Można więc powiedzieć, że int length = myObject.Length bez pozwolenia myObject.Length = 10
Michael Brown
19

Pary metod Gettera i Settera są zapachem kodu.

To błędne założenie i całkowicie niepoprawne. Metody Get / Set są sposobem na enkapsulację elementu danych i nie są w żaden sposób „zapachem kodu”. Naprawdę nienawidzę sposobu, w jaki niektórzy ludzie używają terminu „zapach kodu”, ale w każdym razie ...

To może się zmienić w przyszłości dla dowolnej nieruchomości. Załóżmy, że w wersji 1.0 uzyskanie dostępu do PropertyX po prostu zwraca pole. W wersji 1.5, jeśli pole ma wartość null, PropertyX używa wzorca Null Object do utworzenia nowego obiektu null. W wersji 2.0 pole jest dalej sprawdzane za pomocą metody pobierającej w PropertyX.

Ponieważ właściwość staje się coraz bardziej złożona, wskazanie wydajności korzystania z właściwości wydaje się coraz mniej prawdziwe.

Brzmi jak źle zaprojektowany interfejs API, nie rozumiem, jak to jest wina składni właściwości.

Właściwości w języku C # były po prostu cukrem syntaktycznym dla bardzo powszechnego wzoru, który ułatwiał nam życie jako programistów. Jednak obecnie, jeśli chcesz użyć powiązania danych, musisz „użyć” właściwości, więc są one teraz czymś więcej niż cukrem syntaktycznym. Chyba naprawdę nie zgadzam się z żadnym z twoich argumentów i nie rozumiem, dlaczego nie lubisz funkcji językowej, która bezpośrednio obsługuje wspólny wzór.

Ed S.
źródło
1
Dam ci nagrodę za wymyślenie lepszego terminu niż zapach kodu. Wystarczy przeczytać książkę o refaktoryzacji, w której jest używana około tysiąca razy. To jest jak paznokcie na tablicy.
JeffO
1
@Jeff O: Tak, uważam, że ludzie, którzy wydają się rzucać tym terminem najczęściej, nie mają dużego doświadczenia.
Ed S.
6
@Jeff O i @Ed S: IME, „zapach kodu” stał się powszechnym terminem, którego ludzie używają, gdy naprawdę mają na myśli „Nie lubię tego, ale tak naprawdę nie mam powodu”
Steven Evers
3
@SnOrfus: Tak, lub kiedy mają „religijne” poglądy, które często nie mają większego sensu w praktyce, na przykład „metoda nigdy nie powinna mieć więcej niż X linii” , co z kolei jest po prostu powtórzeniem czegoś, co gdzieś czytają.
Ed S.
1
Nieodpowiednie stosowanie metod getter / setter jest zapach kodu, ale tak też powinno być nieodpowiednie wykorzystanie czegokolwiek . Nawet jeśli rzeczy mają wąskie przypadki użycia, stosowanie takich rzeczy w tych przypadkach użycia nie powinno być uważane za zapach kodu. Tworzenie seterów do wszystkiego nie powinno być ślepym nawykiem, ale nie należy bać się włączać ich, gdy jest to właściwe. Konieczne jest zrównoważenie użyteczności dla klientów w zakresie możliwości zmiany stanu, w porównaniu do możliwości dowiedzenia się, jaki był wcześniej stan (łatwe, jeśli stan jest niezmienny). Oba są przydatne, ale kod musi wybrać jeden.
supercat
10

Twoje założenie jest złe.

Właściwości nie są w żaden sposób umową o wykonanie, wewnętrzną realizację lub cokolwiek innego.
Właściwości to specjalne pary metod, które semantycznie reprezentują atrybut, jeśli wolisz. A zatem jedyną umową jest to, że właściwość zachowuje się tak, jak można się spodziewać po atrybucie.
Jeśli pytam o kolor obiektu, nie zakładam, czy jest on uzyskiwany przez zwykły dostęp do pola, czy też jest obliczany na czas.
Chodzi o to, aby mieć możliwość ujawnienia zachowania atrybutu za pomocą metod, podczas gdy jest on przejrzysty dla konsumenta interfejsu, bez względu na to, czy używasz pola, czy akcesoriów.

Posiadanie atrybutów (i faktycznie ukrywanie ich implementacji, ponieważ właściwości przeciwstawiają się polom) jest potężną funkcją deklaratywną , która jest podstawą do posiadania inspektorów obiektów wizualnych i innych automatycznych generowań widoków, do wiązania danych i wielu innych przydatnych rzeczy. A co najważniejsze, wyraźnie przekazuje te informacje również innym programistom.

back2dos
źródło
6

Konsument myśli z właściwego sposobu myślenia OOP. Jako konsument interfejsu API jestem zainteresowany interakcją z zachowaniem obiektu. Kiedy widzę właściwości w interfejsie API, wygląda bardzo podobnie do stanu. W rzeczywistości, jeśli właściwości robią za dużo, nie powinny nawet być właściwościami, więc tak naprawdę właściwości w stanie API ARE są takie, jakie wyglądają dla konsumentów.

Właściwość ma być stanem. Jeśli bazowy program ustawiający lub kod gettera zmieni się, aby znacznie zwiększyć przetwarzanie wymagane do ustawienia lub uzyskania stanu, to tak naprawdę nie jest to już właściwość i należy ją zastąpić metodami. To zależy od ciebie, jako autora kodu.

Umieszczanie za dużo (ile to za dużo zależy) kodu w seterze lub getterze jest złe, ale tylko dlatego, że jest to możliwe, nie jest powodem do odrzucenia wzorca we wszystkich przypadkach.

ChrisF
źródło
6

Jednej rzeczy brakuje, a nie wiem, czy jest to spowodowane ignorancją, czy celowo przeoczacie ten szczegół, że właściwości są metodami.

Gdy używasz składni właściwości C #, kompilator po cichu tworzy metody pobierające i ustawiające za pomocą metadanych, które mówią językom, które rozumieją właściwości jako pierwszorzędną funkcję składniową, aby traktowały je jako takie. To jest cukier syntaktyczny, o który prosisz. Kilka języków, które można uruchomić na CLR, nie ukrywa przed Tobą całkowicie tego szczegółu (Boo, jeśli pamięć mi służy i niektóre implementacje Lisp), i możesz jawnie wywoływać metody pobierające i ustawiające.

Właściwości czasami powodują skutki uboczne, takie jak wyzwalanie zdarzeń powiadomienia o zmianie (na przykład INotifyPropertyChanged) lub oznaczanie instancji klasy jako brudną. Tutaj mają swoją prawdziwą wartość, choć ich tworzenie to trochę więcej pracy (z wyjątkiem Boo, który ma makra zrozumiałe pod względem składni).

Teraz szerszym pytaniem jest, czy metody pobierające i ustawiające są w rzeczywistości Dobrą Rzeczą. Istnieją wyraźne kompromisy; jeśli masz metody mutatora, twój kod jest z natury mniej równoległy, ponieważ musisz teraz poradzić sobie z problemami z synchronizacją wątków. I całkiem możliwe, że zaryzykujesz naruszeniem Prawa Demetera przy użyciu metod mutatora (niezależnie od tego, czy nazywane są właściwościami, czy metodami getter / setter; są one równoważne), ponieważ jest to cholernie wygodne.

Ale czasem jest to właściwe. Czasami twoim problemem jest pobranie danych z jakiegoś źródła, zmiana ich trochę, przedstawienie zaktualizowanych danych użytkownikowi i zapisanie zmian. Ten idiom jest dobrze obsługiwany przez właściwości. Jak mówi artykuł Allena Holuba , to, że osoby pobierające i ustawiające mają problemy, nie oznacza, że ​​nigdy nie powinieneś ich używać. (Parroting abstract Guruspeak uważany za szkodliwy). Nawet jeśli zastosujesz podejście Klasa / Obowiązki / Współpracownicy, nadal ujawniasz komuś informacje lub prezentacje informacji; chodzi o to, aby zminimalizować pole powierzchni splątania.

Zaletą właściwości jest to, że bardzo łatwo jest skorzystać z innego obiektu. Minusem właściwości jest to, że bardzo łatwo jest skorzystać z innego obiektu i nie można temu łatwo zapobiec.

Mutacja obiektowa ma sens w warstwie kontrolera, na przykład w architekturze MVC. To twój współpracownik. Twój pogląd jest także współpracownikiem, ale nie powinien bezpośrednio mutować twoich obiektów, ponieważ ma różne obowiązki. Wstawianie kodu prezentacji do obiektów biznesowych niekoniecznie jest dobrym sposobem na uniknięcie programów pobierających / ustawiających.

Równanie zmienia się nieco, jeśli używasz funkcjonalnych, a nie czystych OO, abstrakcji, co sprawia, że ​​robienie kopii obiektu „rekordowego” z kilkoma zmianami jest dość trywialne, choć nie wolne. I hej, jeśli próbujesz uzyskać gwarancje wydajności, właściwości są ogólnie bardziej przewidywalne niż leniwe przebudowywanie niezmiennej kolekcji.

JasonTrue
źródło
5

Innym ważnym powodem w mojej książce do używania właściwości jest to, że mogą one znacznie zwiększyć czytelność.

account.setBalance(Account.getBalance()+deposit);

jest po prostu znacznie mniej czytelny niż

account.Balance += deposit;
apoorv020
źródło
6
Z wyjątkiem tego, że Saldo nie powinno być własnością, ponieważ z pewnością będzie istotna logika biznesowa związana z jego zmianą (sprawdź przekroczenie salda; nalicz opłatę za usługę; zapisz transakcję itp.) Twój punkt czytelności jest całkowicie ważny, jeśli zastosujesz go do innego przykładu ( Temperatura, Kolor tła itp.)
Kate Gregory
9
Dlaczego nie konto. Depozyt (kwota)?
xofz
4
@Sam Pearson: +1. Doskonały przykład tego, dlaczego osoby pobierające / ustawiające często wskazują na zły projekt.
Nemanja Trifunovic
4

Masz prawie przeciwny religijny punkt widzenia do mnie :)

Kiedy przeniosłem się z Delphi na Javę, brak właściwości był dla mnie ogromnym afrontem. Byłem przyzwyczajony do deklarowania właściwości i albo kierowania jej bezpośrednio do zmiennej prywatnej, albo pisania (chronionego) gettera i settera, a następnie „podłączania” ich do właściwości. To zamknęło właściwość i kontrolowało, w jaki sposób należy do niej uzyskać dostęp w wyraźny, jednoznaczny sposób. Możesz mieć właściwość tylko do odczytu, która oblicza sumę po uzyskaniu dostępu i nazywa ją „Suma” nie „_getTotal ()” lub podobne ballochs. Oznaczało to również, że można ograniczyć dostęp do właściwości, chroniąc je w abstrakcyjnej klasie bazowej, a następnie przenosząc je do publicznych lub publikowanych w podklasach.

Dla mnie właściwości są bardziej naturalnym i ekspresyjnym sposobem ustawiania i uzyskiwania stanu obiektu. Poleganie na niewymuszonych konwencjach kodowania jest bardziej „zapachem kodu” niż czymkolwiek, za co krytykuje się właściwości. Ponadto, jak powiedzieli inni, wymyślanie źle zaprojektowanego użycia właściwości i wykorzystywanie jego wad do wypróbowania i odrzucenia koncepcji właściwości w ogóle jest wyjątkowo złą formą. Możliwe, że widziałeś tylko złe wykorzystanie właściwości i zakładam, że tak właśnie jest, ale powinieneś zrobić więcej badań, zanim staniesz się zbyt dogmatyczny.

Mcottle
źródło
+1 To rzeczywiście prawdziwe wykorzystanie nieruchomości. Świetna odpowiedź. „ Oznaczało to również, że można ograniczyć dostęp do właściwości, chroniąc je w abstrakcyjnej klasie bazowej, a następnie przenosząc je do publicznych lub publikując w podklasach.
Karthik Sreenivasan
Delphi niewłaściwie wykorzystuje właściwości ad nauseam. Nie sortujesz listy, ustawiasz jej sorted właściwość na true. Tak więc ustawienie na falsedaje oryginalną listę. : D Czy to losowo? : D Cokolwiek, to po prostu głupie. Dodatkowo jest cholernie wolny w porównaniu z odpowiednio posortowanym zestawem. Właściwości nie są złe, ale nauczyłem się ich używać bardzo oszczędnie (do tego stopnia, że ​​jestem całkiem zadowolony z getterów i seterów; używam głównie Javy).
maaartinus
1

Jednym z powodów, dla których właściwości zostały wprowadzone w Java Beans Framework, było umożliwienie integracji z IDE - możesz przeciągnąć te komponenty do IDE i edytować właściwości za pomocą edytorów właściwości.

(wtedy byli zwykłymi pobieraczami i seterami - i zostali zdefiniowani tylko przez konwencję nazewnictwa - i to rzeczywiście pachniało)

Obecnie jest jeszcze więcej przypadków, w których właściwości są uzyskiwane i modyfikowane nie za pomocą zwykłego kodu - na przykład podczas debugowania.

Ophir Yoktan
źródło
1

Z jednej strony - naprawdę pochodzą z VB. Pamiętaj, że w mrocznych czasach XX wieku, kiedy wymyślono platformę .NET, główny nacisk położono na to, że była to łatwa, zastępcza wymiana VB, dzięki czemu programiści VB mogli po prostu przeciągać i upuszczać elementy na formularze internetowe. VB miał właściwości, więc trzeba było zachować tę funkcję, aby wszystko dobrze się tłumaczyło.

Wyatt Barnett
źródło
1
Anders Heljsberg zaprojektował C # (i część IL), a także zaprojektował Delphi - który miał właściwości.
Jesse C. Slicer
1

Istnieją co najmniej dwa cele dotyczące nieruchomości:

  • Są one koncepcyjnie identyczne z polami, nawet jeśli są zaimplementowane inaczej. Getter nie powinien zmieniać stanu obiektu i nie powinien mieć żadnych skutków ubocznych. Seter powinien zmieniać stan tylko w sposób koncepcyjnie podobny do modyfikowania pola i nie wywoływać innych skutków ubocznych.

  • Są one składniowo identyczne z polami publicznymi (prawdopodobnie tylko do odczytu). Oznacza to, że pole publiczne można zmienić na właściwość bez przerywania wywołujących na poziomie źródła.

dsimcha
źródło
Tak, ale zwróć uwagę na słowo „powinno”. Nie ma nic w właściwościach, które zapobiegałyby efektom ubocznym getterów i faktycznie widziałem wiele przypadków, w których tak było.
Nemanja Trifunovic
1
Zmiana pola publicznego na właściwość spowoduje przerwanie zgodności binarnej, zużyty kod będzie musiał zostać ponownie skompilowany - chociaż nie modyfikowany, co, jak sądzę, miałeś na
myśli
@MattDavey: Dzięki. To miałem na myśli. Edytowane.
dsimcha