Dziedziczenie - dostęp klasy potomnej do metod

0

Na wykładzie miałem dziedziczenie i facet podawał przykład, taki że w klasie bazowej są metody, z których niektóre klasy potomne nie będą/nie powinny/nie mogą korzystać i to miał być przykład dziedziczenia, ale coś tu jest nie tak, bo klasy potomne nie powinny mieć dostępu do metod z klasy bazowej, jeżeli użycie tych metod jest nie potrzebne i bezsensu. Mam racje?
W książce head first design patterns jest przykład z kaczkami i tam zastosowali strategie, chociaż z drugiej strony akurat w przykładzie z wykładu już nigdy nic nie będzie modyfikowane/dodawane, ale jak ktoś będzie chciał użyć na obiekcie np. z tej książki gumowej kaczki i sprawić, żeby latała, to będzie źle.

0

taki że w klasie bazowej są metody, z których niektóre klasy potomne nie będą/nie powinny/nie mogą korzystać

ale coś tu jest nie tak, bo klasy potomne nie powinny mieć dostępu do metod z klasy bazowej, jeżeli użycie tych metod jest nie potrzebne i bezsensu

O co Ci chodzi? Przecież oboje, wykładowca i ty macie takie same zdanie.

0

http://pl.wikipedia.org/wiki/Zasada_otwarte-zamkni%C4%99te
http://pl.wikipedia.org/wiki/Hermetyzacja_(informatyka)

jeżeli użycie tych metod jest nie potrzebne i bezsensu (...) w przykładzie z wykładu już nigdy nic nie będzie modyfikowane/dodawane

nigdy nie możesz być tego pewnym
metody powinny być niedostępne jeżeli są składową większej operacji która nie powinna być uruchamiana osobno

0

Na wykładzie miałem dziedziczenie i facet podawał przykład, taki że w klasie bazowej są metody, z których niektóre klasy potomne nie będą/nie powinny/nie mogą korzystać i to miał być przykład dziedziczenia,

Ale o co chodzi? W językach C++, Java, C# itd takie metody robi się prywatne i wtedy klasy dziedziczące z nich korzystać nie mogą. Nie można powiedzieć, że metody prywatne są złe, bo to zależy od wykorzystania.

0
dam1an napisał(a):

taki że w klasie bazowej są metody, z których niektóre klasy potomne nie będą/nie powinny/nie mogą korzystać

ale coś tu jest nie tak, bo klasy potomne nie powinny mieć dostępu do metod z klasy bazowej, jeżeli użycie tych metod jest nie potrzebne i bezsensu

O co Ci chodzi? Przecież oboje, wykładowca i ty macie takie same zdanie.

Nie, bo on twierdzi, że wszystko jest dobrze w jego przykładzie, a ja widzę, że niektóre klasy mogą korzystać z metod, które są im niepotrzebne, mogą powodować błędy i nie maja sensu.

1

A ja widzę dzisiaj pochmurne niebo z przejaśnieniami i przelotnym deszczem. Tak sobie możemy gadać. Może zamieścisz ten przykład?

0
Kasper napisał(a):

Nie, bo on twierdzi, że wszystko jest dobrze w jego przykładzie, a ja widzę, że niektóre klasy mogą korzystać z metod, które są im niepotrzebne, mogą powodować błędy i nie maja sensu.

przecież nie o tym był przykład - podczas krótkiego wykładu nie można pokazać wszystkich praktyk programowania - chodziło o pokazanie dziedziczenia a nie idealnego programu wykorzystującego dziedziczenie
równie dobrze mógłbyś się przyczepić że przykład z książki o kaczkach jest nierealny i nie ma obsługi wyjątków

Kasper napisał(a):

niektóre klasy mogą korzystać z metod, które są im niepotrzebne, mogą powodować błędy i nie maja sensu.

jesteś pewien? niepotrzebne ukrycie metody może tylko utrudnić niepotrzebnie życie. Programista powinien wiedzieć co robi i jeśli wywołuje jakąś metodę to nie bez powodu

Przykład z życia: w androidzie od kilku lat jest bug: https://code.google.com/p/android/issues/detail?id=35482
Jego ominięcie polega na wywołaniu metody changeValueByOne kontrolki po jej pokazaniu
Niestety twórcy uznali żeby oznaczyć tę metodę jako prywatną w związku z czym tysiące programistów jest zmuszonych wywoływać tę metodę z użyciem refleksji. Dodatkowo bug nadal nie jest poprawiony nawet w najnowszej wersji androida

0

A co w sytuacji, kiedy jakaś klasa ma korzystać z metody w klasie bazowej, a inna nie powinna ? Rozbijać to na interfejsy?

0

A jak mysle że wykładowcy chodziło o:
http://en.wikipedia.org/wiki/Fragile_base_class

0

@Kasper, klasa dziedzicząca nie musi korzystać ze wszystkich metod klasy bazowej. Możesz mieć metody, których używa jedna klasa dziedzicząca, a druga nie.

0

Ok, a jeżeli ktoś inny będzie sobie wywoływał metody z obiektu klasy dziedziczącej, które nie mają sensu? To nie będzie prowadziło do błędów.

0
Kasper napisał(a):

Ok, a jeżeli ktoś inny będzie sobie wywoływał metody z obiektu klasy dziedziczącej, które nie mają sensu? To nie będzie prowadziło do błędów.

Moze byc to objawem zlej architektury i zlamania zasady ISP:
http://en.wikipedia.org/wiki/Interface_segregation_principle

0
Kasper napisał(a):

a jeżeli ktoś inny będzie sobie wywoływał metody z obiektu klasy dziedziczącej, które nie mają sensu? To nie będzie prowadziło do błędów.

zazwyczaj jeżeli programista będzie wywoływał metody bez sensu to będzie prowadziło to do błędów...
zadajesz dziwne pytania :D

0

Chodzi mi o dostępność metod z poziomu obiektu, które nie mają żadnego zastosowania z tym obiektem. Bo tak będzie w dziedziczeniu np. z tą kaczką, mamy klasę kaczka i klasy po niej dziedziczące i jest sobie klasa gumowa kaczka, korzystając z obiektu typu tej klasy można wywołać metodę leć, która nie ma sensu w tym przypadku.

0

@Kasper to się nazywa błąd projektowy. Skoro nie każda kaczka może latać to nie możesz mieć metody "leć" w klasie bazowej kaczka. Zresztą gumowa kaczka niewiele ma wspólnego ze zwykłą kaczką. Zrobienie takiego dziedziczenia oznacza że zupełnie "nie czujesz" tematu.

0

zawsze operacja może być wirtualna a w funkcji realizującej można napisać

public override void Leć()
{
  throw new InvalidOperationException("Głupi? Gumowe kaczki nie latają");
}

często się spotyka takie coś - czy jest to błąd w projekcie? Niekoniecznie - często dziedziczymy po cudzych klasach które nie przewidywały istnienie naszej

0

Uważam, że jest to błąd w projekcie. Czasem takie rzeczy się robi wybierając mniejsze zło konieczne, ale to dla mnie wcale nie jest ok.

0

@gsdfgdsf: Ten code smell polega na tym, ze gdy sami stworzylismy interfejsy, a pozniej podczas ich implementacji czesto musimy rzucac OperationNotSupported to powinno nam dac to do myslenia, ze jednak te interfejsy nie sa dobrze przemyslane i trzeba je rozbic na mniejsze.

0

To jest złamanie zasady separacji interfejsów i zasady podstawiania i jest to błąd. Co nie znaczy że się nie zdarza. Czasem tak bywa że trzeba by przepisać sporo bo zmieniły się wymagania klienta i szybciej zrobić takiego "hacka". W rzeczywistośsci należałoby wydzielic nową bazę która tego latania nie ma i tej bazy używać wszędzie, a tam gdzie każemy kaczce latać używać bazowej kaczki latającej dziedziczącej z tej podstawowej kaczki.

0

Taka sytuacja byłaby w przypadku gdybyśmy implementowali gatunki ptaków. Wszystkie latają i jest ok. Przychodzi jednak potrzeba zaimplementowania strusia. No strusie nie latają. No wtedy by trzeba wydzielić klasę PtakiLatajace. W praktyce nie zawsze jest tak prosto i, tak jak @Shalom napisał, obchodzi się problem takimi nieładnymi hackami

0
gsdfgdsf napisał(a):

zawsze operacja może być wirtualna a w funkcji realizującej można napisać

public override void Leć()
{
  throw new InvalidOperationException("Głupi? Gumowe kaczki nie latają");
}

InvalidOperationException można rzucać, gdy próbujemy pisać do strumienia, który już zamknęliśmy. Jeśli jakaś nadpisywana metoda nie ma sensu, to rzucamy NotSupportedException.

często się spotyka takie coś - czy jest to błąd w projekcie? Niekoniecznie - często dziedziczymy po cudzych klasach które nie przewidywały istnienie naszej

Tutaj zgoda - przykład: klasa Stream (w .NET) ma właściwość Position. DeflateStream dziedziczy ze Stream, ale pozycja w kompresowanym strumieniu raczej nie ma sensu, więc rzuca wyjątek.
Czy wydzielanie oddzielnego interfejsu na strumienie z pozycją i komplikowanie przez to hierarchii klas oraz ich użyć, miałoby większy sens niż rzucenie wyjątku w przypadku jednej klasy?

0

Jak czasem tak trzeba to rzucaj po prostu UnsupportedOperationException.

tak jak np. Java:

package app;

import java.util.Arrays;
import java.util.List;


public class Main {
    public static void main(String[] args) {

        List<String> words = Arrays.asList("abc", "def", "ghi");
        try {
            words.add("ijk");
        } catch (UnsupportedOperationException uoe) {
            System.out.println("bo niemodyfikowalna");
        }

    }
}
0

U mnie na uczelni nagminne jest to, że prowadzący robią takie dziedziczenia w skomplikowanych algorytmach obliczeniowych. I co wtedy zrobić, jeżeli obiekt typu klasy potomnej powinien/ma prawo korzystać z 20 metod z klasy bazowej , a z 10 nie powinien/ jest to niezgodne z algorytmem i nie ma sensu? Przecież nie będę robił różnych hacków, bo to będzie masakra, ani robić z tego interfejsy bo to też będzie masakra.
Czyli można by zastosować wzorzec strategia i wyrzucać błędy w wypadku wywoływania czegoś czego nie chcemy? To nie będzie WTf?

0

pokaż kod i przestań już pisać "bez sensu, bez sensu" albo zmień nicka na "smerf maruda"

Kasper napisał(a):

I co wtedy zrobić, jeżeli obiekt typu klasy potomnej powinien/ma prawo korzystać z 20 metod z klasy bazowej , a z 10 nie powinien/ jest to niezgodne z algorytmem i nie ma sensu?

po pierwsze już jest skopane na wstępie bo 20 metod w klasie wygląda na god object
po drugie jeżeli połowa z nich należy do konkretnego algorytmu a dziedziczą z niego inne to dziedziczenie jest z d**y

ogólnie przy algorytmach rzadko się stosuje dziedziczenie

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