Wiem, że wydaje się to dziwnym pytaniem, ponieważ celem dwóch lub więcej obiektów dzielących tę samą klasę jest to, że ich zachowanie jest takie samo, tzn. Ich metody są identyczne.
Jestem jednak ciekawy, czy istnieją języki OOP, które pozwalają na nowo zdefiniować metody obiektów w taki sam sposób, w jaki można przypisać różne wartości dla ich pól. W rezultacie powstałyby obiekty zbudowane z tej samej klasy, które nie wykazują już dokładnie takiego samego zachowania.
Jeśli się nie mylę, możesz zrobić ten JavaScript? Wraz z tym pytaniem pytam, dlaczego ktoś miałby to zrobić?
object-oriented
programming-languages
Niko Bellic
źródło
źródło
setClickHandler()
metody i sprawić, że różne instancje tej samej klasy robią bardzo różne rzeczy. W językach, które nie mają wygodnych wyrażeń lambda, łatwiej jest utworzyć nową anonimową podklasę tylko dla nowego modułu obsługi. Tradycyjnie metody zastępujące były uważane za znak rozpoznawczy nowej klasy, podczas gdy ustawianie wartości atrybutów nie było, ale zwłaszcza w przypadku funkcji obsługi, oba mają bardzo podobne efekty, więc rozróżnienie staje się wojną o słowa.Odpowiedzi:
Metody w większości (opartych na klasach) językach OOP są ustalane według typu.
JavaScript jest oparty na prototypach, a nie na klasach, więc możesz nadpisywać metody w oparciu o instancje, ponieważ nie ma wyraźnego rozróżnienia między „klasą” a obiektem; w rzeczywistości „klasa” w JavaScript jest obiektem, który przypomina szablon, w którym powinny działać instancje.
Każdy język, który zezwala na pierwszorzędne funkcje, Scala, Java 8, C # (przez delegatów) itp., Może działać tak, jakbyś miał przesłonięcia metod dla poszczególnych instancji; musisz zdefiniować pole z typem funkcji, a następnie zastąpić je w każdej instancji.
Scala ma inną możliwość; W Scali możesz tworzyć singletony obiektowe (używając słowa kluczowego object zamiast słowa kluczowego class), dzięki czemu możesz rozszerzyć klasę i zastąpić metody, w wyniku czego nowa instancja tej klasy bazowej zostanie zastąpiona.
Dlaczego ktoś miałby to robić? Powodów może być dziesiątki. Może być tak, że zachowanie musi być dla mnie ściślej zdefiniowane, niż byłoby to możliwe przy użyciu różnych kombinacji pól. Może także lepiej oddzielić kod i lepiej go zorganizować. Ogólnie jednak uważam, że te przypadki są rzadsze i często istnieje prostsze rozwiązanie wykorzystujące wartości pól.
źródło
Trudno odgadnąć motywację twojego pytania, więc niektóre możliwe odpowiedzi mogą, ale nie muszą dotyczyć twojego prawdziwego zainteresowania.
Nawet w niektórych nieprototypowych językach możliwe jest przybliżenie tego efektu.
Na przykład w Javie anonimowa klasa wewnętrzna jest bardzo zbliżona do tego, co opisujesz - możesz utworzyć i utworzyć instancję podklasy oryginału, zastępując tylko metodę lub metody, które chcesz. Klasa wynikowa będzie klasą
instanceof
oryginalną, ale nie będzie tą samą klasą.Dlaczego chcesz to zrobić? W przypadku wyrażeń lambda Java 8 myślę, że wiele najlepszych przypadków użycia zniknie. Przynajmniej we wcześniejszych wersjach Javy można uniknąć rozprzestrzeniania się prostych i wąskich klas. To znaczy, gdy masz dużą liczbę powiązanych przypadków użycia, różniących się tylko niewielkim funkcjonalnym sposobem, możesz tworzyć je niemal w locie (prawie), z różnicą behawioralną wprowadzaną w odpowiednim momencie.
To powiedziawszy, nawet przed J8, często można to zmienić, aby przesunąć różnicę na pole lub trzy i wstrzyknąć je do konstruktora. Oczywiście w przypadku J8 samą metodę można wstrzyknąć do klasy, choć może pojawić się pokusa, aby zrobić to, gdy kolejne refaktoryzowanie może być czystsze (jeśli nie tak fajne).
źródło
Poprosiłeś o dowolny język zapewniający metody dla poszczególnych instancji. Jest już odpowiedź na Javascript, więc zobaczmy, jak to się robi w Common Lisp, gdzie można używać specjalizatorów EQL:
Dlaczego?
Specjalizatory EQL są przydatne, gdy argument podlegający wysłaniu ma typ, który
eql
ma sens: liczbę, symbol itp. Ogólnie rzecz biorąc, nie potrzebujesz go i po prostu musisz zdefiniować tyle podklas, ile potrzebne przez twój problem. Ale czasami wystarczy wysłać tylko zgodnie z parametrem, który jest na przykład symbolem:case
wyrażenie byłoby ograniczone do znanych przypadków w funkcji wysyłania, podczas gdy metody można dodawać i usuwać w dowolnym momencie.Specjalizacja w instancjach jest również przydatna do celów debugowania, gdy chcesz tymczasowo sprawdzić, co dzieje się z określonym obiektem w uruchomionej aplikacji.
źródło
Możesz to również zrobić w Ruby, używając obiektów singletonowych:
Produkuje:
Jeśli chodzi o zastosowania, tak właśnie Ruby wykonuje metody klas i modułów. Na przykład:
W rzeczywistości definiuje metodę singleton
hello
naClass
obiekcieSomeClass
.źródło
extend
tak naprawdę tworzy klasę singleton dla obiektu, a następnie importuje moduł do klasy singleton.Można pomyśleć o metodach dla poszczególnych instancji, które pozwalają na tworzenie własnej klasy w czasie wykonywania. Może to wyeliminować wiele kodów kleju, które nie mają innego celu niż połączenie dwóch klas, aby ze sobą rozmawiać. Mixiny są nieco bardziej ustrukturyzowanym rozwiązaniem tego samego rodzaju problemów.
Trochę cierpisz z powodu paradoksu blub , w gruncie rzeczy trudno jest dostrzec wartość funkcji języka, dopóki nie użyjesz jej w prawdziwym programie. Szukaj więc okazji, w których Twoim zdaniem może to zadziałać, wypróbuj je i zobacz, co się stanie.
Poszukaj w kodzie grup klas, które różnią się tylko jedną metodą. Poszukaj klas, których jedynym celem jest połączenie dwóch innych klas w różnych kombinacjach. Poszukaj metod, które nie robią nic innego, jak przekazywać wywołanie do innego obiektu. Poszukaj klas, które są tworzone za pomocą złożonych wzorców tworzenia . Są to wszyscy potencjalni kandydaci, którzy zostaną zastąpieni metodami dla poszczególnych instancji.
źródło
Inne odpowiedzi pokazały, w jaki sposób jest to wspólna cecha dynamicznych języków obiektowych i jak można ją trywialnie emulować w języku statycznym, który ma obiekty funkcji pierwszej klasy (np. Delegaty w c #, obiekty, które zastępują operator () w c ++) . W językach statycznych, które nie mają takiej funkcji, jest to trudniejsze, ale nadal można to osiągnąć za pomocą kombinacji wzorca strategii i metody, która po prostu przekazuje jego implementację strategii. Jest to w rzeczywistości to samo, co robisz w języku c # z delegatami, ale składnia jest nieco nieporządna.
źródło
Możesz zrobić coś takiego w C # i większości innych podobnych języków.
źródło
Koncepcyjnie, nawet jeśli w języku takim jak Java wszystkie instancje klasy muszą mieć te same metody, możliwe jest, aby wyglądały tak, jakby nie były, poprzez dodanie dodatkowej warstwy pośredniej, być może w połączeniu z klasami zagnieżdżonymi.
Na przykład, jeśli klasa
Foo
może zdefiniować statyczną abstrakcyjną klasę zagnieżdżoną,QuackerBase
która zawiera metodęquack(Foo)
, a także kilka innych statycznych klas zagnieżdżonych pochodzących zQuackerBase
każdej z nich z własną definicjąquack(Foo)
, to jeśli klasa zewnętrzna ma polequacker
typuQuackerBase
, to może ustaw to pole, aby zidentyfikować (ewentualnie singleton) instancję dowolnej z zagnieżdżonych klas. Po wykonaniu tej czynności wywołaniequacker.quack(this)
spowoduje wykonaniequack
metody klasy, której instancja została przypisana do tego pola.Ponieważ jest to dość powszechny wzorzec, Java zawiera mechanizmy do automatycznego deklarowania odpowiednich typów. Takie mechanizmy tak naprawdę nie robią niczego, czego nie można było zrobić, używając po prostu metod wirtualnych i opcjonalnie zagnieżdżonych klas statycznych, ale znacznie zmniejszają ilość płyty kotłowej niezbędną do stworzenia klasy, której jedynym celem jest uruchomienie jednej metody w imieniu inna klasa.
źródło
Uważam, że taka jest definicja języka „dynamicznego”, takiego jak ruby, groovy i Javascript (i wiele innych). Dynamiczny odnosi się (przynajmniej częściowo) do możliwości dynamicznego redefiniowania zachowania instancji klasy w locie.
Nie jest to ogólnie dobra praktyka OO, ale dla wielu programistów z dynamicznym językiem zasady OO nie są ich najwyższym priorytetem.
Upraszcza to niektóre skomplikowane operacje, takie jak łatanie małp, w których można ulepszyć instancję klasy, aby umożliwić interakcję z zamkniętą biblioteką w sposób, którego nie przewidzieli.
źródło
Nie twierdzę, że warto to robić, ale w Pythonie jest to trywialnie możliwe. Nie mogę sobie wyobrazić dobrego przypadku użycia z głowy, ale jestem pewien, że istnieją.
źródło