• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Programowanie obiektowe - zastosowanie

Object Storage Arubacloud
+1 głos
775 wizyt
pytanie zadane 9 września 2018 w C# przez KacperSuperSax Nowicjusz (160 p.)
Mam pytanie, może głupie (pewnie tak), może mądre, nie wiem. Uczę się o klasach. metodach, konstruktorach itp., wszystko wydaje się być super, zrozumiałe, intuicyjne ale! jakoś nie mogę dostrzec zastosowania obiektówki. W przykładowych, małych programach jakoś nie ma to sensu, kupy się nie klei, przez co też nie widzę jakoś też tego w zastosowaniu na szerszą skalę.

Mógłby mi ktoś to wytłumaczyć, jak to razem działa, z czym to się klei, pokazać jakieś sensowne wzorce projektowe, ew. pokazać jakiś kod do własnego przeanalizowania? Chcę to po prostu zrozumieć, bo samą teorią człowiek nie wyżyje.
komentarz 9 września 2018 przez RafalS VIP (122,820 p.)
W jakim jezyku ten kod chcesz?
komentarz 9 września 2018 przez KacperSuperSax Nowicjusz (160 p.)
C# byłby spoko, ale z braku laku JS też może być
komentarz 10 września 2018 przez Wiciorny Ekspert (269,710 p.)

@RafalS, Obiektowość tłumaczyć najlepiej na modelu abstrakcji, nie jest wazny język :) ...

samo modelowanie wystarcza 

3 odpowiedzi

+2 głosów
odpowiedź 9 września 2018 przez Crash182 Gaduła (3,600 p.)
wybrane 10 września 2018 przez KacperSuperSax
 
Najlepsza

Tak jak kolega wcześniej wspomniał, chodzi głownie o porządek i czytelność. Dodatkowo należy tutaj pamiętać o 3 głównych filarach programowania obiektowego: dziedziczenie, polimorfizm i enkapsulacja. Tak dla przykładu smieszny kod, który własnie naskrobałem żeby Ci mniej więcej pokazać na jakimś banalnym przykładzie, dlaczego?....  

public class Video
    {
        // video odtwarza kasety, pamieta ktos jeszcze? :D wiec nasz obiekt video powstaly na bazie tej klasy bedzie mogl przechowywac jedna kasete
        // ten pojemnik na kasete jest prywatny, bo uzytkownik nie powinien miec do niego besposredniego dostepu
        // aby wlozyc lub wyciagnac kasete, musi uzyc przyciskow Insert / Eject w ktory jest schowana jakas dodatkowa logika
        private Cassette _cassette;


        // nasze video bedzie mialo tez status, tutaj zrobilem dla odmiany property ale z private set, bo status jest wynikiem jakies operacji
        // podobnie jak z kaseta uzytkownik nie moze sobie sam po prostu zmienic status
        public Status Status { get; private set; }

        public Stopwatch Timer { get; }

        public void On()
        {
            Status = Status.On;
            Display("Welcome");
        }

        public void Off()
        {
            Status = Status.Off;
            Display("Goodbye");
        }

        public void Play()
        {
            Status = Status.Playing;

            // programuja obiektowo mozesz zrobic takie sztuczki, w zaleznosci jaki kaseta ma tytuł, to własnie wyswietli nasze video
            Display($"Now Playing: {_cassette.Title}");

            Timer.Start();

            // tak ze niby jak kaseta sie skonczy to video ma zrobic stop :P
            if (Timer.ElapsedMilliseconds >= _cassette.Time)
                Timer.Reset();
        }

        public void Pause()
        {
            Status = Status.Pause;
            Display("Paused");
            Timer.Stop();
        }

        public void Stop()
        {
            Status = Status.Stop;
            Display("Stopped");
            Timer.Reset();
        }

        public void Rev()
        {
            Status = Status.Reverse;
            Display("Revercing");
        }

        public void Forward()
        {
            Status = Status.Forward;
            Display("Forwarding");
        }

        public void Insert(Cassette cassette)
        {
            if (_cassette == null)
                _cassette = cassette;
            else
                Display("Cassete alredy in!");

        }

        public void Eject()
        {
            // powiedzmy ze zeby nie uszkodzic glowicy, jesli video odtwarza albo przewija kasete
            // kaseta najpierw musi zostac zatrzymana
            if (Status != Status.Stop)
                Stop();

            _cassette = null;
        }

        private void Display(string message)
        {
            // jakas logika odpowiedzialna za wyswietlanie wiadomosci uzytkownikowi video
            // metoda ta jest prywatna bo uzytkownik nie powinien miec mozliwosci sam sobie wyswietlac wiadomosci
            // ENKAPSULACJA \o/ czyli jeden z filarow OOP no i code reuse, pisze logige odpowiedzialna za wyswietlanie tylko jeden raz
            // pozniej inne komponenty jej uzywaja
        }

    }

    public class Cassette
    {
        public string Title { get; set; }
        public long Time { get; set; }
    }

    public enum Status
    {
        On,
        Off,
        Playing,
        Pause,
        Stop,
        Forward,
        Reverse
    }

I tak dalej, można to rozbudowywać w nieskończoność, pomyśl np że wideo jest zbudowane z wielu komponentów, jakiś procesor, jakieś mechanizmy poruszania kasetą, głowica itd, To wszystko mogą (a nawet powinny) być osobne obiekty z których video będzie się składać. Obiekt głowica będzie miał w sobie kod odpowiedzialny za robotę głowicy, a video powinno tylko kazać głowicy np zacząć odczytywać taśmę gry zostanie odpalona przez użytkownika metoda Play(), i tak dalej i tak dalej..... jak można tutaj zauważyć, piękno takiego podejścia to to że jest jakiś wysoko poziomowy moduł, np to nasze video, i on deleguje prace niższym modułom, a te z kolei jest jest taka potrzeba delegują pracę jeszcze niższym modułom. Programista czytają taki kod nie widzi plamy błota przed sobą a poukładane instrukcje i tylko od niego zależy jak głęboko chce kopać. Może jak czytasz kod, wystarczy że wiesz kiedy głowica się odpala a nie interesuje cię konkretnie kod, jak ona to robi że czyta taśmę. Ład i porządek. 

Pozdrawiam

+5 głosów
odpowiedź 9 września 2018 przez marcin99b Szeryf (82,160 p.)
Chodzi po prostu o porządek i czytelność
Wszystko da się zrobić bez tego, ale po pewnym czasie zaczniesz się gubić

I to w sumie tyle
Można mówić że jak mamy interfejsy to tam refleksjami można wyciągać obiekty zamiast ręcznie wklepywać blablabla
Ale wszystko ostatecznie sprowadza się do właśnie czytelności

Pracując dłużej nad jakimś projektem, jeśli będzie napisany obiektowo, jest mniejsza szansa że się pogubisz (prostsze do zrozumienia, bo bardziej naturalny sposób wyobrażania sobie programu przez ludzi -> jako obiekty)

Prościej wyobrazić sobie że masz np psa i kota, i że to są zwierzęta
Że każde coś robi, ale pies ma swoje dodatkowe opcje i kot to samo

Niż wyobrazić sobie aplikacje za pomocą dajmy na to funkcji -> które ludzie często wyobrażają sobie, jako rurki połączone ze sobą
komentarz 10 września 2018 przez NowyUrzydgownig Mądrala (5,090 p.)
Chodzi też o łatwość modyfikacji.
komentarz 10 września 2018 przez marcin99b Szeryf (82,160 p.)
No też, ale łatwość modyfikacji według mnie zalicza się do "porządek i czytelność "
0 głosów
odpowiedź 9 września 2018 przez RafalS VIP (122,820 p.)
edycja 9 września 2018 przez RafalS

nie widzę jakoś też tego w zastosowaniu na szerszą skalę.

Poczytaj historie paradygmatów programowania. Programowanie obiektowe powstało właśnie dlatego, że podejście prodecuralne, a jeszcze wcześniej strukturalne nie sprawdzało się w dużych systemach. Ciężko było utrzymywać dużą aplikacje napisaną proceduralnie.

Koniec końców wszystko rozbija się o ogarnięcie dużej aplikacji przez programistów. O czytelność kodu. 

Przykładowo gdy zobaczysz sobie 1000 linijek instrukcji napisanych w mainie to ciężko się to czyta, no nie? Nie daj boże są w tym kodzie jakieś skoki do losowych miejsc. Taki kod jest nieczytelny i masakryczny w utrzymaniu (modyfikacji).

Dlatego wymyślili podejśćie proceduralne. Kod stał się troche czytelniejszy, main jest szeregiem nazwanych funkcji operujących na danych przesłanych w argumentach.

Ale jeśli aplikacja jest na prawdę duża to masa danych (zmiennych) i funkcji w obszarze globalnym powoduje, że można się co najwyżej w tym wszystkim pogubić. Np masz strukture (klasa bez metod) i szereg funkcji przyjmujących tą strukture jako argument. Widać, że jest potrzeba połączenia danych z funkcjami, które na nich operują. I to jest właśnie kwintesencja obiektowości. Połączenie danych (zmiennych) z zachowaniem (funkcjami).

Programowanie obiektowe wprowadza także pewien poziom abstrakcji. Pewnego ukrywania bebechów. Tak jak człowiek na codzień posługuje się interfejsami, gdy używa pilota do telewizora czy lewarka skrzyni biegów tak programista może zrobić to samo. Gdy wciskasz czerwony przycisk na pilocie do TV to nie interesuje Cię w jaki sposób sygnał dociera do telewizora i jak telewizor te sygnał przetwarza. Interesuje Cię co możesz z tym pilotem zrobić. Jak się z nim obchodzić. Programowanie obiektowe pozwala w ten sposób projektować kod.

Każda klasa udostępnia pewien interfejs publiczny do komunikacji z innymi klasami jednocześnie ukrywając implementacje. Jest to w pewien sposób naturalny dla ludzi sposób myślenia o rzeczywistości.

Dam przykład. Tablica dynamiczna z której wszyscy korzystamy. Róznie ją nazywają - vector, arraylist, list. Wyobraż sobie jak by wyglądało korzystanie z tablicy dynamicznej gdyby była napisana proceduralnie. Miałbyś w obszarze GLOBANYM zmienna capacity określającą obecną pojemność (ile jeszcze mozna elementow do tablicy dodac zanim trzeba bedzie ja powiekszyć) i size - czyli ilość elementów w tablicy. Miałbyś też szereg wolnych funkcji przyjmujących jako argumenty właśnie te zmienne, które składają się na tablice dynamiczną:

addToList(int capacity, int size, int[] tab, int element_to_add);

removeFromList(int capacity, int size, int []tab)

printList(int size, int []tab);

Na pierwszy rzut oka widać nadmiarowość w postaci nazw funkcji: ...toList ...fromList ...List. Te funkcje sa połączone ze zmiennymi tylko nazwami i wszystko jest w obszarze globalnym. Język w żaden sposób ich nie łączy, mimo, że są przeznaczone do operowania na tych właśnie danych. Kolejny minus to integralność danych. Programista korzystający z listy może sobie ją zepsuć modyfikując capacity samemu. Np capacity jest 10 a programista podaje, ze jest 100. Program sie wysypuje.

Odpowiedz na wszystkie te problemy to programownaie obiektowe. Nie trzeba doawać do nazw funkcji podkreslenia że są przeznaczone do listy, bo ligoczna struktura języka wiaże je z listą. 

Gwarantowana jest też integralność danych. Nikt z zewnątrz nie zmodyfikuje Ci zmiennej capacity i nie zepsuje listy.

Kod jest czytelny (nazwy), łatwy w utrzymaniu (zmienne prywatne) i wygodnie się z niego korzysta:

Lista list;
list.add(10);
lista.print();
lista.remove();

Mam nadzieje, że coś pomogłem. Programowanie obiektowe to o wiele więcej niż to co napisałem, ale mam nadzieje, że zrozumiesz jego istotę i sens.

EDIT: Opisywałem w innym wątku na czym polega abstrakcja, która jest bardzo ważna w programowaniu obiektowym. Rzuć okiem: https://forum.pasja-informatyki.pl/376120/abstrakcja-wyjasnienie#a376159

EDIT2: Zapomniałem dodać co jest super fajnego w obiektowej liście. Chodzi o to, że gdy zrobimy inną kolekcje np liste jednokierunkową to nazwy metod mogą być takie same (add, remove, print) ze względu na zmiane  zasięgu. Można też zauważyć, że obydwie listy udostępniają podobne funkcjonalności i można wydobyć z nich jeden wspólny interfejs. Te same funkcjonalności inna implementacja - polimorfizm. Praca z takim kodem i jego utrzymanie jest niewyobrażalnie łatwe w porównaniu z podejściem proceduralnym.

komentarz 10 września 2018 przez Aisekai Nałogowiec (42,190 p.)

Praca z takim kodem i jego utrzymanie jest niewyobrażalnie łatwe w porównaniu z podejściem proceduralnym.

W teorii. W praktyce, może się okazać że kod będzie na tyle skomplikowany i na tyle "nieczysto napisany", że może się okazać, że nawet podejście obiektowe nic nie pomoże, a nawet przeszkodzi. I czasami kod napisany proceduralnie może się lepiej czytać czy modyfikować, niż niepotrzebnie skomplikowany kod napisany (żeby byl) obiektowo.

Miałbyś w obszarze GLOBANYM zmienna capacity określającą obecną pojemność

Lokalnie też się da.  Jeżeli lista byłaby lokalna, nic nie stoi na przeszkodzie by capacity tez było lokalne. 

Dobrze, że wspomniałeś o polimorfizmie i interfejsach, a nie o dziedziczeniu którego uzywanie dużo problemów może sprawiać

Podobne pytania

0 głosów
1 odpowiedź 405 wizyt
pytanie zadane 10 kwietnia 2018 w C# przez patrykkxdd Początkujący (310 p.)
0 głosów
2 odpowiedzi 426 wizyt
pytanie zadane 27 października 2018 w JavaScript przez kameleon Użytkownik (590 p.)
0 głosów
1 odpowiedź 358 wizyt
pytanie zadane 21 października 2018 w C i C++ przez leonka Nowicjusz (120 p.)

92,565 zapytań

141,418 odpowiedzi

319,602 komentarzy

61,951 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...