Forum Coders' city Strona Główna Coders' city
Nasza pasja to programowanie!
 

 PomocPomoc   SzukajSzukaj   UżytkownicyUżytkownicy   GrupyGrupy  RejestracjaRejestracja 
Archiwum starego forum + teoria    RSS & Panel/SideBar
 ProfilProfil   Zaloguj się, by sprawdzić wiadomościZaloguj się, by sprawdzić wiadomości   ZalogujZaloguj 

Potrzebuję szybkiej odpowiedzi na moje pytanie... Zasady

[TypeScript] Sprawdzenie, czy obiekt implementuje określony interfejs



 
Odpowiedz do tematu    Forum Coders' city Strona Główna -> ECMAScript
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Luke



Dołączył: 17 Cze 2007
Posty: 1893
Skąd: Szczecin

PostWysłany: Czw Lip 14, 2016 1:36 pm  OP    Temat postu: [TypeScript] Sprawdzenie, czy obiekt implementuje określony interfejs Odpowiedz z cytatem Pisownia

Dla treningu tworzę edytor diagramów i w ramach rozwoju zdecydowałem się za skorzystanie z TypeScriptu, chociażby dlatego, że implementuje nowości nieobsługiwane jeszcze w przeglądarkach i transpiluje je do ECMAScriptu 5.

Chciałbym, aby niektóre bloki mogły mieć zmieniany rozmiar, a inne nie, dodatkowo niektóre np. tylko jednocześnie w pionie i poziomie ("po skosie").

Pierwsze, co nasuwa mi się na myśl, to stworzenie odpowiednich interfejsów, które będzie implementować klasa reprezentująca dany blok - ResizableHorizontal, ResizableVertical, ResizableDiagonal.

Niestety TypeScript nie pozwala na dynamiczne sprawdzenie, czy obiekt implementuje interfejs.
(I tak - nie miałem pomysłu na tytuł wątku.)
Więc jedyne, co mi pozostaje, to umieszczenie w bazowej dla wszystkich bloków w klasie wielu pól typu Boolean - isHorizontalResizable, isVerticalResizable... a to jakoś nie wygląda dobrze.

Proszę o sugestie, jak można zaimplementować to jakoś ładniej. :)

_________________
Moje projekty | Tani hosting
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora
marcin_an



Dołączył: 26 Maj 2005
Posty: 18822

PostWysłany: Czw Lip 14, 2016 3:21 pm      Temat postu: Odpowiedz z cytatem Pisownia

Nie piszę w TypeScripcie, więc będę odpowiadał trochę "na ślepo". Ponieważ jednak twój problem jest bardziej ogólnoobiektowy niż TypeScriptowy, nie powinno to stanowić większego kłopotu.

Przede wszystkim wpadłeś w pułapkę problemu circle-ellipse*. I to w podręcznikowym przykładzie! Napraw to, a twój problem zniknie. Najprościej będzie przez przejście na używanie obiektów niemodyfikowalnych. Wtedy będziesz miał hierarchię interfejsów opartą na getterach:
  • Rectangle
    • getWidth
    • getHeight
  • Square extends Rectangle
    • getWidth
    • getHeight
    • Gwarancja: getWidth() is getHeight() dają ten sam wynik.
Jeśli z jakiegoś powodu musisz mieć mutatory, obetnij problem z drugiej strony. Czyli zdejmij gwarancje z getterów i oprzyj interfejs na setterach. Wtedy masz:
  • Square
    • setSize
    • getWidth
    • getHeight
    • Gwarancja: setSize(x) powoduje, że getWidth() i getHeight() dają x.
  • Rectangle extends Square
    • setWidth
    • setHeight
    • setSize
    • getWidth
    • getHeight
Jeżeli potrzebujsz setterów oraz gwarancji na gettery, rozdziel to na dwie niezależne hierarchie, bo w takiej sytuacji te interfejsy nie są ze sobą związane (pomimo wrażenia, że są**). Jeżeli potrzebujesz mieć między nimi jakiś związek, to dodaj metodę konwertującą:
  • Square
    • setSize
    • getSize
    • getRectangle - zwraca Rectangle o szerokości i wysokości równej getSize()
  • Rectangle
    • setWidth
    • setHeight
    • getWidth
    • getHeight
    • getBoundingSquare - zwraca kwadrat zawierający*** ten prostokąt
Metody te mogą też być odwrotnie zrobione: tzn. Square ma konstruktor/fabrykę tworzącą go z Rectangle, a Rectangle fabrykę**** tworzącą ze Square.

Sprawa druga: po wpadnięciu w circle-ellipse wybrałeś najgorszą możliwą metodę jego rozwiązania, czyli złamanie podstawowego prawa obiektowości: LSP. Chcesz sprawdzić, czy obiekt jest daną implementacją określonego interfejsu i na tej podstawie zmieniać widoczne***** działanie swojego kodu. Tego nie wolno robić - łamiesz w ten sposób abstrakcję i zaprzeczasz celowi, dal którego w ogóle stosujesz obiektowość.

____
* Znanego także jako "square-rectangle".
** Właśnie z tego wynika problem circle-ellipse - podobieństwo okręgu i elipsy powoduje, że ludziom wydaje się, że są ze sobą związane.
*** Alternatywnie lub dodatkowo może to być np. kwadrat zawarty w prostokącie.
**** Nie może mieć konstruktora, bo będzie niejednoznaczny - pozostaje tylko fabryka.
***** Co innego zastosowanie tego do optymalizacji, logowania albo napisania "niskopoziomowego" helpera, który z założenia operuje na typach obiektów (ale też: na wszystkich mających sens, a nie kilku z góry wybranych).
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość
Luke



Dołączył: 17 Cze 2007
Posty: 1893
Skąd: Szczecin

PostWysłany: Czw Lip 14, 2016 3:35 pm  OP    Temat postu: Odpowiedz z cytatem Pisownia

Mądrze piszesz, ale chyba niezbyt konkretnie opisałem swój problem. :|

Otóż na podstawie listy obiektów chcę później rysować je na płótnie i umożliwiać zmianę rozmiaru, np. tylko po skosie.
Chcę uzyskać informację, czy można zmienić rozmiar danego bloku i w jaki sposób.

_________________
Moje projekty | Tani hosting
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora
marcin_an



Dołączył: 26 Maj 2005
Posty: 18822

PostWysłany: Czw Lip 14, 2016 7:04 pm      Temat postu: Odpowiedz z cytatem Pisownia

Niczego to nie zmienia. Nadal masz circle-ellipse, i nadal próbujesz to rozwiązać poprzez złamanie LSP.

Ta dodatkowa informacja pozwala jedynie zasugerować, że najlepszym rozwiązaniem będzie prawdopodobnie trzecie. Tyle tylko, że trochę zmodyfikowane. W te chwili zdajesz się mieć klasę odpowiedzialną za rysowanie, która traktuje kwadraty i prostokąty (tudzież bboxy obiektów - na jedno wychodzi) jako pasywną przechowywalnię danych. Natomiast to owe kwadraty i prostokąty powinny zajmować się rysowaniem. A w zasadzie dowolne kszałty, bo w takiej sytuacji przestajesz być ograniczony do dwóch. Zatem model powinien wyglądać tak, jak w załącznikach model1.

Ponieważ prawdopodobnie będziesz też chciał mieć jakieś opcje konfiguracji kształtu do tego, każdy z obiektów może dostarczać własny interfejs konfiguracyjny. Przykładowo w model2 jest to pokazane, gdzie rolę tę pełni Configurator. Gdy aplikacja potrzebuje interfejsu do ustalenia parametrów obiektu x, uzyskuje instancję Configurator poprzez wywołanie x.getConfigurator. Uzyskany obiekt posiada oczywiście referncję "zwrotną" do x. Następnie aplikacja prosi o zainstalowanie się wewnątrz określonego elementu (np. diva) poprzez wywołanie installUi. Metoda ta dodaje wszystkie potrzebne pod-elementy, eventy itd. Obsługa zdarzeń jest wykonywana wewnątrz implementacji Configurator, które - mając referncję do x - ustawia mu co trzeba.

Można iść dalej i uniezależnić generowanie szczegółów interfejsu konfiguracyjnego od konkretnej implementacji Configurator, ale nie chciałem jeszcze bardziej komplikować obrazu sprawy. Gdybyś jednak chciał, to installUi będzie korzystało ze wzorca odwiedzającego, który dostaje informację o kolejnych potrzebnych rodzajach elementów UI (np. polach tekstowych, polach numerycznych, opcjach wyboru, listach, ...) wraz z metainformacjami (tytuł pola, domyślna wartość, walidator, callback do informowania o zmianach, ...) i sam sobie generuje zawartość.

Uwaga: diagramy obydwu przedstawionych modeli są uproszczone i brakuje niektórych metod i parametrów potrzebnych do prawidłowego działania - diagramy te mają jedynie przedstawić omawianą ideę.



model2.png
 Opis:
Rendering model2.uxf

Pobierz
 Nazwa pliku:  model2.png
 Wielkość pliku:  8.46 KB
 Pobierano:  53 raz(y)


model2.uxf
 Opis:
Model 2

Pobierz
 Nazwa pliku:  model2.uxf
 Wielkość pliku:  5.73 KB
 Pobierano:  59 raz(y)


model1.png
 Opis:
Rendering model1.uxf

Pobierz
 Nazwa pliku:  model1.png
 Wielkość pliku:  4.22 KB
 Pobierano:  52 raz(y)


model1.uxf
 Opis:
Model 1

Pobierz
 Nazwa pliku:  model1.uxf
 Wielkość pliku:  2.61 KB
 Pobierano:  53 raz(y)

Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość
Luke



Dołączył: 17 Cze 2007
Posty: 1893
Skąd: Szczecin

PostWysłany: Czw Lip 14, 2016 11:30 pm  OP    Temat postu: Odpowiedz z cytatem Pisownia

Głównie mam problem z tym, w jaki sposób zaimplementować rysowanie ramki wokół elementu oraz ustawianie odpowiednich kursorów, jeśli można zmieniać rozmiary obiektu.

Dziedziczenie raczej odpada, bo TS pozwala dziedziczyć tylko po jednej klasie.
Zalecany sposób implementacji mixinów jest wg mnie z kolei zbyt "toporny".

_________________
Moje projekty | Tani hosting
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora
marcin_an



Dołączył: 26 Maj 2005
Posty: 18822

PostWysłany: Pią Lip 15, 2016 12:38 am      Temat postu: Odpowiedz z cytatem Pisownia

Luke napisał:
Głównie mam problem z tym, w jaki sposób zaimplementować rysowanie ramki wokół elementu oraz ustawianie odpowiednich kursorów, jeśli można zmieniać rozmiary obiektu.
Przecież opisałem, jak to zrobić. Drugi (ew. trzeci) sposób opisany w moim poprzednim poście.

Luke napisał:
Dziedziczenie raczej odpada, bo TS pozwala dziedziczyć tylko po jednej klasie.
Zalecany sposób implementacji mixinów jest wg mnie z kolei zbyt "toporny".
O niczym takim nie pisałem - nie wiem zatem, do czego się tutaj odwołujesz.
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość
Wyświetl posty z ostatnich:   
Odpowiedz do tematu    Forum Coders' city Strona Główna -> ECMAScript Wszystkie czasy w strefie CET (Europa)

Strona 1 z 1

 
Skocz do:  
Możesz pisać nowe tematy
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Możesz dodawać załączniki na tym forum
Możesz pobierać pliki z tego forum




Debug: strone wygenerowano w 0.17620 sekund, zapytan = 13
contact

| Darmowe programy i porady Jelcyna | Tansze zakupy w Helionie | MS Office Blog |