Uczę się, jak tworzyć OOP za pomocą JavaScript . Czy ma koncepcję interfejsu (np. Java interface
)?
Więc mógłbym stworzyć słuchacza ...
javascript
oop
Tom Brito
źródło
źródło
Odpowiedzi:
Nie ma pojęcia, że „ta klasa musi mieć te funkcje” (to znaczy brak interfejsów jako takich), ponieważ:
Zamiast tego JavaScript używa tak zwanego pisania kaczego . (Jeśli chodzi jak kaczka i kwakuje jak kaczka, jeśli chodzi o JS, jest to kaczka.) Jeśli twój obiekt ma metody quack (), walk () i fly (), kod może użyć go tam, gdzie się spodziewa obiekt, który może chodzić, kwakać i latać, bez konieczności implementacji jakiegoś interfejsu „Duckable”. Interfejs jest dokładnie zestawem funkcji, z których korzysta kod (i zwracanymi wartościami z tych funkcji), a przy wpisywaniu kaczki dostajesz to za darmo.
Nie oznacza to, że kod nie zawiedzie w połowie, jeśli spróbujesz zadzwonić
some_dog.quack()
; otrzymasz TypeError. Szczerze mówiąc, jeśli każesz psom kwakać, masz nieco większe problemy; pisanie na kaczkach działa najlepiej, gdy trzymasz wszystkie kaczki w rzędzie, że tak powiem, i nie pozwalasz, aby psy i kaczki zlewały się ze sobą, chyba że traktujesz je jak zwierzęta ogólne. Innymi słowy, mimo że interfejs jest płynny, nadal tam jest; częstym błędem jest podanie psa do kodu, który oczekuje, że będzie kwakał i latał w pierwszej kolejności.Ale jeśli masz pewność, że postępujesz właściwie, możesz obejść problem psiaka, sprawdzając, czy istnieje konkretna metoda, zanim spróbujesz jej użyć. Coś jak
Możesz więc sprawdzić wszystkie metody, których możesz użyć przed ich użyciem. Jednak składnia jest trochę brzydka. Jest nieco ładniejszy sposób:
Jest to standardowy JavaScript, więc powinien działać w każdym interpretatorze JS, którego warto użyć. Ma dodatkową zaletę czytania jak angielski.
W przypadku współczesnych przeglądarek (czyli praktycznie każdej przeglądarki innej niż IE 6-8) istnieje nawet sposób, aby nie wyświetlać się w
for...in
:Problem polega na tym, że w ogóle nie ma obiektów IE7
.defineProperty
, a w IE8 podobno działa tylko na obiektach hosta (czyli elementach DOM i tym podobnych). Jeśli problemem jest kompatybilność, nie możesz jej użyć.defineProperty
. (Nie wspomnę nawet o IE6, ponieważ jest on raczej nieistotny poza Chinami.)Inną kwestią jest to, że niektóre style kodowania zakładają, że każdy pisze zły kod, i zabraniają modyfikowania
Object.prototype
w przypadku, gdy ktoś chce na ślepo używaćfor...in
. Jeśli Ci na tym zależy lub używasz ( zepsutego IMO ) kodu, który działa, wypróbuj nieco inną wersję:źródło
for...in
jest - i zawsze był - obarczony takimi niebezpieczeństwami, a każdy, kto to zrobi, nie biorąc pod uwagę, że ktoś dodał doObject.prototype
(nietypowa technika, jak przyznaje ten artykuł), zobaczy, że jego kod łamie się w czyichś rękach.for...in
problemu. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…for...in
problem” nadal będzie do pewnego stopnia istniał, ponieważ zawsze będzie niechlujny kod ... no cóż, iObject.defineProperty(obj, 'a', {writable: true, enumerable: false, value: 3});
to jest o wiele więcej pracy niż tylkoobj.a = 3;
. Całkowicie rozumiem ludzi, którzy nie próbują tego robić częściej. : POdbierz kopię „ wzorców projektowych JavaScript ” autorstwa Dustina Diaza . Jest kilka rozdziałów poświęconych implementacji interfejsów JavaScript poprzez Duck Typing. To także miła lektura. Ale nie, nie ma natywnej implementacji interfejsu dla języka, musisz typ kaczki .
źródło
JavaScript (ECMAScript edycja 3) ma
implements
zarezerwowane słowo zapisane do wykorzystania w przyszłości . Myślę, że jest to przeznaczone właśnie do tego celu, jednak w pośpiechu, aby wydostać się ze specyfikacji, nie mieli czasu na określenie, co z nią zrobić, więc w chwili obecnej przeglądarki nie robią nic poza pozwól mu tam usiąść i od czasu do czasu narzekać, jeśli spróbujesz użyć go do czegoś.Możliwe jest i naprawdę łatwe stworzenie własnej
Object.implement(Interface)
metody z logiką, która błąka się za każdym razem, gdy określony zestaw właściwości / funkcji nie jest zaimplementowany w danym obiekcie.Napisałem artykuł o orientacji obiektowej, w którym stosuję własną notację w następujący sposób :
Jest wiele sposobów na skórowanie tego konkretnego kota, ale taką logikę zastosowałem przy własnej implementacji interfejsu. Uważam, że wolę takie podejście i jest łatwe do odczytania i użycia (jak widać powyżej). Oznacza to dodanie metody „implementuj”, z
Function.prototype
którą niektórzy mogą mieć problem, ale uważam, że działa ona pięknie.źródło
var interf = arguments[i]; for (prop in interf) { if (this.prototype[prop] === undefined) { throw 'Member [' + prop + '] missing from class definition.'; }}
. Zobacz bardziej szczegółowy przykład na dole linku do artykułu .Interfejsy JavaScript:
Chociaż JavaScript nie ma tego
interface
typu, często jest potrzebny. Z przyczyn związanych z dynamicznym charakterem JavaScript i wykorzystaniem Prototypical-Inheritance trudno jest zapewnić spójne interfejsy między klasami - jednak jest to możliwe; i często emulowane.W tym momencie istnieje kilka konkretnych sposobów emulacji interfejsów w JavaScript; wariancja podejść zazwyczaj zaspokaja niektóre potrzeby, podczas gdy inne pozostają bez odpowiedzi. Często najbardziej niezawodne podejście jest zbyt uciążliwe i utrudnia implementację (programistę).
Oto podejście do interfejsów / klas abstrakcyjnych, które nie jest zbyt uciążliwe, objaśniające, ogranicza implementacje wewnątrz abstrakcji do minimum i pozostawia wystarczająco dużo miejsca na dynamiczne lub niestandardowe metodologie:
Uczestnicy
Precept Resolver
Ta
resolvePrecept
funkcja jest funkcją narzędziową i pomocniczą do użycia wewnątrz klasy abstrakcyjnej . Jego zadaniem jest umożliwienie dostosowanej obsługi implementacji enkapsulowanych Wskazań (dane i zachowanie) . Może rzucać błędy lub ostrzegać - ORAZ - przypisywać wartość domyślną do klasy Implementor.iAbstractClass
iAbstractClass
Określa interfejs jest używany. Jego podejście wymaga milczącej umowy z klasą Implementor. Ten interfejs przypisuje każde przykazanie dokładnie tej samej przestrzeni nazw przykazań - LUB - do wszystkiego, co zwraca funkcja Rozpoznanie przykazań . Jednak milcząca umowa rozwiązuje się w kontekście - postanowienie Implementora.Realizator
Implementator po prostu „zgadza się” z interfejsem ( iAbstractClass w tym przypadku) i stosuje je przez użycie Konstruktor-Hijacking :
iAbstractClass.apply(this)
. Poprzez zdefiniowanie powyższych danych i zachowania, a następnie przejęcie konstruktora interfejsu - przekazanie kontekstu implementatora do konstruktora interfejsu - możemy zagwarantować, że zostaną dodane przesłonięcia implementatora, a interfejs wyjaśni objaśnienia i wartości domyślne.Jest to bardzo nieporęczne podejście, które służyło mojemu zespołowi i mnie bardzo dobrze na czas i różne projekty. Ma jednak pewne zastrzeżenia i wady.
Wady
Chociaż pomaga to w znacznym stopniu zaimplementować spójność w oprogramowaniu, nie implementuje prawdziwych interfejsów, ale je emuluje. Chociaż definicje, domyślne, a ostrzeżenia lub błędy są wyjaśniony, wyjaśnianiu obsługi jest egzekwowane i zapewnił przez programistę (podobnie jak w przypadku większości skryptów JavaScript).
To pozornie najlepsze podejście do „Interfejsów w JavaScript” , jednak chciałbym zobaczyć rozwiązanie:
delete
działaniamiTo powiedziawszy, mam nadzieję, że to pomoże ci tak bardzo, jak mój zespół i ja.
źródło
Potrzebujesz interfejsów w Javie, ponieważ jest on wpisany statycznie, a kontrakt między klasami powinien być znany podczas kompilacji. W JavaScript jest inaczej. JavaScript jest dynamicznie wpisywany; oznacza to, że po otrzymaniu obiektu możesz po prostu sprawdzić, czy ma określoną metodę i wywołać go.
źródło
yourMethod
pozycję 5 wSuperclass
tabeli vtable, a dla każdej podklasy, która ma własnąyourMethod
, po prostu wskazuje pozycję tej podklasy 5 przy odpowiednim wdrożeniu.Implementation
która implementujeSomeInterface
, nie tylko mówi, że implementuje cały interfejs. Zawiera informacje z napisem „WdrażamSomeInterface.yourMethod
” i wskazuje definicję metody dlaImplementation.yourMethod
. Gdy JVM wywołujeSomeInterface.yourMethod
, szuka w klasie informacji o implementacjach metody tego interfejsu i stwierdza, że musi zadzwonićImplementation.yourMethod
.Mam nadzieję, że każdy, kto wciąż szuka odpowiedzi, uzna ją za pomocną.
Możesz wypróbować za pomocą serwera proxy (jest to standard od ECMAScript 2015): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Następnie możesz łatwo powiedzieć:
źródło
Jeśli chcesz użyć transkompilatora, możesz wypróbować TypeScript. Obsługuje projekty funkcji ECMA (we wniosku interfejsy nazywane są „ protokołami ”) ”) podobne do języków, takich jak coffeescript lub babel.
W TypeScript twój interfejs może wyglądać następująco:
Czego nie możesz zrobić:
źródło
w JavaScript nie ma natywnych interfejsów, istnieje kilka sposobów symulacji interfejsu. napisałem paczkę, która to robi
możesz zobaczyć implantację tutaj
źródło
JavaScript nie ma interfejsów. Ale można go wpisać w kaczkę, przykład można znaleźć tutaj:
http://reinsbrain.blogspot.com/2008/10/interface-in-javascript.html
źródło
Wiem, że to stary, ale ostatnio odkryłem, że potrzebuję coraz więcej przydatnych narzędzi API do sprawdzania obiektów pod kątem interfejsów. Więc napisałem to: https://github.com/tomhicks/methodical
Jest również dostępny przez NPM:
npm install methodical
Zasadniczo robi wszystko, co sugerowano powyżej, z pewnymi opcjami dotyczącymi bycia bardziej rygorystycznymi, a wszystko to bez konieczności wykonywania wielu zadań
if (typeof x.method === 'function')
.Mam nadzieję, że ktoś uzna to za przydatne.
źródło
To stare pytanie, ale ten temat nigdy nie przestaje mnie męczyć.
Ponieważ wiele odpowiedzi tutaj i w Internecie koncentruje się na „wymuszaniu” interfejsu, chciałbym zasugerować alternatywny widok:
Na przykład mam generator e-maili, który spodziewa się otrzymywać fabryki sekcji e-mail , które „wiedzą”, jak wygenerować zawartość sekcji i kod HTML. Dlatego wszyscy muszą mieć jakieś metody
getContent(id)
igetHtml(content)
metody.Głównym wyzwaniem związanym z tym wzorcem jest to, że metody muszą albo być
static
argumentem samej instancji, aby uzyskać dostęp do jej właściwości. Są jednak przypadki, w których uznaję to za kompromisowe.źródło
taki abstrakcyjny interfejs
utwórz instancję:
i użyj go
źródło