Klasa abstrakcyjna a interfejs

Klasa abstrakcyjna a interfejs
0

Dzień dobry. Spotkałem się z twierdzeniem, że klasa abstrakcyjna to szkielet (rozumiem to jako same definicje metod). Z drugiej strony, czytałem, że jeśli klasa abstrakcyjna posiada same metody abstrakcyjne (definicje) to warto ją zastąpić interfejsem. Jakie jest Wasze zdanie na ten temat?

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
1

Interfejs to kontrakt - opisuje co klasa go implementująca ma robić, podczas gdy klasa abstrakcyjna dodatkowo może opisywać jak dana rzecz się dzieje (tzn. może zawierać stan oraz implementację).

Zwyczajowo podstawą do komunikacji między modułami aplikacji są interfejsy, choć - jak wszędzie - należy podchodzić do tego z głową ;-)


edytowany 1x, ostatnio: Patryk27
kchteam
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 7 lat
  • Lokalizacja:Tychy
  • Postów:155
2

W programowaniu zorientowanym obiektowo chodzi o zamodelowanie w kodzie rzeczywistości.

Interfejs definiuje sposób użycia obiektu, który go implementuje - określa jakie ten posiada metody publiczne i jakie parametry przyjmuje. Jeden interfejs mogą implementować różne klasy, które nie są ze sobą w ogóle powiązane.

Czyli można powiedzieć, ze interfejs, to tylko "instrukcja użycia" obiektu.
Klasa abstrakcyjna sama w sobie już coś reprezentuje, ale na bardzo wysokim poziomie abstrakcji - można by powiedzieć ogólnie. Może ona posiadać właściwości i może posiadać zachowania (metody), tak jak każda inna klasa, jednak utworzenie obiektu tej klasy nie ma sensu.

Kiedy używać interfejsów, a kiedy klas abstrakcyjnych?
Powiedziałbym, że wszędzie powinniśmy się starać użyć interfejsów, a tam gdzie jest to niewystarczające to klas abstrakcyjnych (co nie znaczy, że klasa abstrakcyjna nie może implementować interfejsu).

Odpowiadając wprost na Twoje pytanie: jeśli mamy klasę abstrakcyjną, która posiada tylko metody abstrakcyjne, to jest doskonały kandydat do zmiany na interfejs.

[Adam]


Jeden zespół, tysiące możliwości!
0

Rozumiem. Wydaje Mi się, że takie zastosowanie klas abstrakcyjnych jest prawidłowe.

Kopiuj
class Client extends ParserClient
{
  ...Zwrócenie wyników metod z HtmlClient i RestClient, w metodach, które może wykorzystać klient w pliku index.php tworzenie obiektu Client np:
    public function clearNameForUser($param)
    {
        return $this->methodWithParserClientOrRestClient($param);
    }
}

abstract class ParserClient extends RestClient
{
  ...Metody Parsowania i to co mają robić
}

abstract class RestClient
{
  ...Metody REST i to co mają robić
}

Jak to rozumiem. W klasie HtmlClient zawarty jest core całej aplikacji, taki backend backendu. Klasy HtmlClient i RestClient są na tyle ogólne, że nie ma sensu tworzenia ich obiektu. Rozdzielenie na klasy ParserClient i RestClient Moim zdaniem ma taki sens, że programista będzie wiedział, gdzie musi szukać metody, jak chce zmienić na przykład jakąś funkcje restową - czyli czytelność kodu. Dlaczego nie stosuję interfejsów w zamiast klas abstrakcyjnych? gdyż nie chcę wszystkiego pchać do klasy Client.

0

Oczywiście mogę się mylić i proszę o wyprowadzenie z błędu i nakierowanie na prawdiłowe tory @Patryk27 @kchteam

kchteam
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 7 lat
  • Lokalizacja:Tychy
  • Postów:155
0

Nie do końca rozumiem Twój opis. Gdzie w tym wszystkim jest klasa HtmlClient? Czy ona jest na tym samym poziomie co RestClient? Jaka jest różnica między RestClient i HtmlClient?
Nieczytelne dla mnie jest użycie metody methodWithParserClientOrRestClient() - nie wiem co ona może robić. Dlaczego implementacja metody clearNameForUser() oddelegowuje jakąś akcję do jakiejś tajemniczej metody.

Ponadto zwróć uwagę na nazwy klas - klasy abstrakcyjne to z założenia klasy ogólne, zatem ich nazwy również powinny być ogólne, a te, które z nich dziedziczą powinny być bardziej szczegółowe. U Ciebie klasy abstrakcyjne to RestClient i ParserClient, a konkretna to Client, czyli odwrotnie ;)

Powiedz coś więcej o całości problemu, który masz do rozwiązania - wtedy łatwiej będzie powiedzieć coś więcej i poukładać odpowiedzialność klas.

[Adam]


Jeden zespół, tysiące możliwości!
edytowany 2x, ostatnio: kchteam
0
Kopiuj
class Client extends ParserClient
{
  ...Zwrócenie wyników metod z ParserClient i RestClient, w metodach, które może wykorzystać klient w pliku index.php tworzenie obiektu Client np:
    public function clearNameForUser($param)
    {
        .metoda zdefuniowana w jednej z klas ParserClient lub RestClient.
        return $this->methodWithParserClientOrRestClient($param);
    }
}
 
abstract class ParserClient extends RestClient
{
  ...Metody Parsowania i to co mają robić
}
 
abstract class RestClient
{
  ...Metody REST i to co mają robić
}

Chciałem zrobić tak, aby klasy RestClient i ParserClient zawierały wszystkie metody do zarządzania aplikacją czyli taki jakby Core systemu, mógłbym te wszystkie metody umieścić w jednej klasie o nazwie Core.php i tą klasą rozszerzać klasę Client, wyszłoby na to samo co jest teraz ale chciałem także klasę Core.php podzielić na dwie inne (celem czytelności), zależnie od tego, co robią, w tym przypadku jedna klasa byłaby odpowiedzialna za parsowanie tekstu(ParserClient) i zwracanie wyniku, a druga klasa za wyciąganie danych ze strony w postaci JSON(RestClient). Klasa Client, zawiera metody, które zwracają wyniki metod z klas ParserClient i RestClient.
Założeniem jest, aby użytkownik w pliku index.php, mógł wywołać wybraną metodę przez

Kopiuj
$show = new Client();
$show->clearNameForUser($param);

Ale faktycznie, z tego co piszesz, klasa Client powinna być tą abstrakcyjną, a nie tamte. Muszę całą strukturę jeszcze przemyśleć. Bo chciałbym, aby użytkownik musiał tworzyć obiekt tylko jednej klasy(w tym przypadku Client) z której może wywoływać metody zarówno z klas ParserClient jak i RestClient.

kchteam
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 7 lat
  • Lokalizacja:Tychy
  • Postów:155
0

W Twoim opisie jest kilka rzeczy, które mnie niepokoją ;)

Chciałem zrobić tak, aby klasy RestClient i ParserClient zawierały wszystkie metody do zarządzania aplikacją czyli taki jakby Core systemu, mógłbym te wszystkie metody umieścić w jednej klasie o nazwie Core.php i tą klasą rozszerzać klasę Client

Nie wiem, co ma robić cała Twoja aplikacja, ale niemal na pewno umieszczenie "wszystkich metod do zarządzania" w jednej lub dwóch klasach jest złym pomysłem. Klasy nie powinny być uniwersalne i zawierać wszystkiego - powinny mieć w miarę wąski zakres zadań - jedną odpowiedzialność. Jednocześnie należy dbać o to, żeby klasy nie były zbyt długie - maksymalnie kilkaset linii i parę metod publicznych. Po czym poznać, że klasa "robi za dużo"? Zwykle ma mnóstwo publicznych metod, zupełnie ze sobą nie powiązanych.

Kolejna rzecz - dziedziczenie zazwyczaj nie jest dobrym pomysłem na rozdzielenie odpowiedzialności klas - znacznie lepiej sprawdzi się skomponowanie obiektów, które muszą coś wykonać (kompozycja) - czyli korzystanie z innych klas w danej klasie, zamiast dziedziczenia po nich.

Jeśli już dziedziczysz, to w Twoim przykładzie metoda clearNameForUser() zupełnie niepotrzebnie deleguje zadanie do innej metody z tej samej klasy. Domyślam się, że chodziło Ci o to, żeby metoda nazywała się tak samo, ale miała różną implementację w zależności od... no własnie czego? W takiej sytuacji są dwa wyjścia: albo możesz metodę clearNameForUser() zrobić jako abstrakcyjną w klasie nadrzędnej i ją implementować w podrzędnych, albo jeśli operacja, którą ta metoda ma wykonać jest złożona, zaimplementować ją w klasie nadrzędnej i poskładać wynik jej działania z kilku abstrakcyjnych metod chronionych (wzorzec metoda szablonowa

Podsumowując - być może w ogóle nie potrzebujesz klas abstrakcyjnych, a zamiast tego szereg klas, z których każda będzie odpowiadała za swój kawałek roboty.

[Adam]


Jeden zespół, tysiące możliwości!
edytowany 1x, ostatnio: kchteam
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)