Fasada i interfejsy

0

Witam,

Potrzebujesz waszej wiedzy, a mianowicie:

Chciałbym zbudować fasadę w oparciu o gotowe API.
Ale mam problem, ponieważ w tym momencie np. funkcjonalności samochodu dostarcza mi interfejs ISamochod ( co mnie trochę dziwi bo przecież to interfejs) , i w kodzie używam instancji interfejsu żeby np. poruszyć samochodem . A chciałbym żeby ten samochód był rozbudowany o dodatkowe funkcje ( choć nie wiem czy tak powinno się tworzyć fasadę ) czyli stworzył bym klasę która dziedziczy po samochodzie i dodał swoją funkcjonalność (oczywiście taka funkcja nie tylko by rozszerzała ale łączyła w bardziej złożoną całość drobiazgowe funkcje także z innych klas a właściwie interfejsów).

Ale skoro to interfejs to nie wiem jak powinienem się za to zabrać. Czy stworzyć w fasadzie porostu np. Klasę MojSamochód która dostarczy mi tych wszystkich bardziej złożonych funkcji?Ale wtedy zwykły ISamochod z API będzie musiał być argumentem tych funkcji bo jak inaczej operować treścią/danymi którą przechowuje taki ISamochód?

Proszę o porządny wykład , który mnie nauczy jak budować fasadę i pewnie skarci mnie za braki w podstawowej wiedzy.

Z góry serdecznie dziękuje

1

Czyli dostajesz gotowe obiekty i chcesz rozszerzyć ich funkcjonalność? W takim razie: http://pl.wikipedia.org/wiki/Dekorator_(wzorzec_projektowy)

1

@Microb ja mam wrażenie że ty w ogóle nie bardzo rozumiesz jak to działa...
To nie jest tak ze masz gdzieś instancje interfejsu. Masz po prostu obiekt klasy która go implementuje, ale wewnątrz konkretnej funkcji "patrzysz na ten obiekt" przez pryzmat tylko tego interfejsu. Robi się tak zwykle po to żebyś mógł do takiej funkcji przekazywać własne implementacje danego interfejsu.
Poza tym do czego ma być tak fasada? Bo nie bardzo rozumiem...

1

Jeżeli potrzebujesz, to interfejs możesz rozbudowywać o nowe funkcjonalności (hipotetyczne) tak samo jak i każdą klasę. Z ta różnicą, że nadal to będzie interfejs, więc żadnej implementacji tam nie będzie. Oczywiście o ile tak zmodyfikowane interfejsy faktycznie będą pełnić u Ciebie jakąś znaczącą rolę z konkretnych klasach. Na przykładzie tego samochodu - Jeżeli jakaś część kodu będzie działać wyłącznie dla samochodów ciężarowych, to robisz
interface ISamochódCiężarowy extends ISamochód {...} i w niektórych klasach go implementujesz (oraz podajesz jako argumenty/wyniki). Nie opłaca się to tylko wtedy gdybyś takich interfejsów musiał zrobić dziesiątki - wtedy prościej jest rozbudować obecny interfejs pojedynczym, który takie "inne" przypadki obejmie.

0

@Wibowit słowo o dekoratorach najbardziej mi pomogło dziękuje.

Co do istniejących już interfejsów którę są w API. Nie rozumiem jakim sposobem obiekt typu ISamochód dostarcza mi jakiejś funcknonalności. tzn. np. getPasażerowie() a dokładnie jakim sposobem coś co jest interfejsem ma ciało funkcji?
Będę wdzięczny jeśli przetłumaczycie mi to.

0

Funkcjonalność interfejsu jest opisana w javadocu interfejsu i jego metod (czy innych elementów). Implementujący musi się tego ściśle trzymać bo inaczej cała implementacja może nie mieć sensu. To samo z klientem, który interfejsu tylko używa - dla niego dokumentacja jest jedynym czego może się trzymać. A w jaki sposób jakiś interfejs jest zrealizowany w konkretnej klasie, to już inna sprawa. Mimo iż posługujesz jakimś interfejsem, to de facto zawsze posługujesz się jakąś klasą konkretną, która go implementuje. Mając referencję do interfejsu i chcąc wywołać jego metodę, to faktycznie masz referencję do jakiejś klasy, która dla Ciebie jest funkcjonalnie ograniczona do możliwości dawanych przez ten interfejs. W kodzie wykonywalnym, interfejs nie istnieje jako byt samodzielny (co innego związany z nim obiekt typu Class<?>, który jednak pełni inną funkcję). Mając taką referencję możesz się nadal dowiedzieć coś o rzeczywistej klasie takiego obiektu (używając refleksji). Referencję "interfejsu" można funkcjonalnie jeszcze bardziej ograniczyć przez rzutowanie jej "w górę" do interfejsu, który ten pierwszy może rozszerzać. Czyli podobnie jak rzutowanie referencji do obiektu na klasę bazową (jakiegoś przodka). Przynajmniej aż do momentu kiedy jakiś interfejs niczego już nie rozszerza bo wtedy (każdy) domyślnie rozszerza niejawny interfejs klasy Object. Dlatego każdą referencję do interfejsu można bez obaw rzutować na Object i dostanie się najbardziej okrojoną funkcjonalność jaka jest możliwa. Jest to możliwe nawet jeżeli interfejs jest tylko markerem, czyli nie posiada w sobie zupełnie niczego (np. RandomAccess).

0

@Microb operujesz zawsze na obiektach klas. Zawsze. Interfejs dostarcza ci tylko pewnego "widoku" obiektu, nic więcej. Tak jakby przypisanie obiektu do referencji na interfejs tak jakby przysłania ci wszystkie metody i pola tego obiektu, zostawiając "widoczne" tylko te które są w interfejsie. Na przykład jeśli mamy:

List<Integer> lista = new ArrayList<Integer>();

To nie znaczy że obiekt "lista" jest nagle obiektem interfejsu List<T>. On nadal jest obiektem ArrayList ale widzimy go jako obiekt który implementuje interfejs List<T>.
Po co tak robić? Głównie po to żeby nie wiązać sie z konkretną implementacją. Jeśli na przykład nasza metoda wymaga jako argumenu listy i nie ma znaczenia czy to będzie LinkedList, ArrayList czy lista którą uzytkownik sam sobie zaimplementował to wtedy jako argumentu możemy użyć właśnie interfejsu. W ten sposób mamy pewność że przekazany obiekt dostarcza pewnej funkcjonalności która w metodzie jest nam potrzebna.
Na przykład metoda sort() może wymagać podania kolekcji obiektów Iterable<T> gdzie T jest Comparable<K>. W ten sposób jest uniwersalna - możemy nią sortować dowolne kolekcje obiektów o ile da się po tej kolekcji itertować i da się porównywać obiekty w tej kolekcji. Bo wewnątrz naszej funkcji te obiekty będą widziane jako Iterable i Comparable i nas nie obchodzi jakie to są obiekty, nas obchodzi tylko jakiej funkcjonalności dostarczają.

1 użytkowników online, w tym zalogowanych: 0, gości: 1