Blog Dla Młodszych Programistów C#/.NET

wtorek, 23 października 2018
Tagi: JavaScript
Dzisiaj wracamy do filarów programowania zorientowanego obiektowo w JavaScript. W poprzednim artykule starałem Ci się przybliżyć na czym polega enkapsulacja, a dzisiaj pomęczymy się abstrakcją :)

Aby zrozumieć czym jest abstrakcja, przedstawię Ci bardzo popularny przykład opisany na podstawie odtwarzacza DVD. Chyba każdy wie jak wygląda taki odtwarzacz (przynajmniej z zewnątrz). Każdy podstawowy odtwarzacz ma jakąś skomplikowaną logikę w środku, ale na zewnątrz ma tylko kilka przycisków, są to między innymi przyciski start, stop, power, dzięki którym możemy komunikować się z tym odtwarzaczem. Konsumentów tego odtwarzacza nie interesuje co się dzieje w środku takiego odtwarzacza, interesuje ich tylko jak włączyć, wyłączyć czy zatrzymać odtwarzacz, no może jeszcze kilka innych funkcji :) Jest to bardzo dobry przykład abstrakcji w praktyce.

Jak mamy rozumieć taką abstrakcję w JavaScript? Ano bardzo prosto, wyobraź sobie jakiś zwykły obiekt na przykład logger, który zapisuje jakieś ważne informacje w pliku tekstowym. Dla prostoty przykłady powiedzmy, że jedyną metodę jaką udostępnia jest metoda zapisz. Użytkownik, który używa tej metody wie, że metoda ta zapisuje przekazany przez niego tekst do pliku tekstowego, ale nie interesują go szczegóły tej implementacji, nie interesują go prywatne metody ani właściwości. Co ważne dzięki temu, że nie ma dostępu do prywatnych metod i właściwości nie naruszy działania publicznej metody. Dodatkowo co by się stało gdybyśmy udostępniali jakąś metodę, która powinna być prywatna i dodalibyśmy do niej jakiś parametr? Wszystkie osoby, które używały tą metodę musiały by również robić mnóstwo zmian. Dzięki stosowaniu abstrakcji, jeżeli zmienimy jakieś metody wewnątrz loggera, które udostępniamy innym to osoba która używa tej metody nie będzie musiała nic zmieniać. Możemy zmienić prywatne metody, właściwości czy parametry ale na zewnątrz nic się nie zmieni i o to nam właśnie chodzi.

Podsumowując ten krótki wstęp abstrakcja mówi o tym, że powinniśmy ukryć szczegóły, a pokazać tylko to co istotne. Tyle teorii, teraz zobaczy to na przykładzie.
function Logger(path) {
    this.path = path;
    this.defaultPath = 'C:\\Logger\\Errors.txt';

    this.save = function() {
        if(!this.path){
            this.setDefaultPath();
        }
        console.log(`Save message - ${this.path}`);
    }

    this.setDefaultPath = function() {
        this.path = this.defaultPath;
    }
}

let logger1 = new Logger('C:\\Logger.txt');
logger1.save('Error'); //Save message - C:\Logger.txt
let logger2 = new Logger();
logger2.save('Error'); //Save message - C:\Logger\Errors.txt
let logger3 = new Logger();
logger3.defaultPath = 'abc';
logger3.setDefaultPath = function () {
    console.log('changed method');
}
logger3.save('Error'); 
//changed method
//Save message - abc
W powyższym przykładzie mamy obiekt Logger, który za pomocą metody Save zapisuje podaną w parametrze wiadomość pod określoną ścieżką. Jeżeli ścieżka nie została podana jako parametr, wówczas plik jest zapisywany pod domyślną ścieżką, przynajmniej takie były założenia, ale jak widać wyszło trochę inaczej. Zobacz na przykład z logger3, przez to że wszystkie właściwości i metody były publiczne użytkownik zmienił sobie całkowicie działanie obiektu logger. Wartość domyślnej ścieżki została zmieniona, a także nawet metoda SetDefaultPath, przez co obiekt nie zachowuje się tak jak powinien. Jak się przed taką sytuacją zabezpieczyć? Należy zrobić to o czym pisałem na początku tego artykułu, to znaczy udostępnić na zewnątrz metody które są istotne, a ukryć szczegóły implementacji. Możemy to zrobić zamieniając właściwości oraz metody w zwykłe zmienne.
function Logger(path) {
    let defaultPath = 'C:\\Logger\\Errors.txt';

    this.save = function() {
        if(!path){
            setDefaultPath();
        }
        console.log(`Save message - ${path}`);
    }

    let setDefaultPath = function() {
        path = defaultPath;
    }
}

let logger1 = new Logger('C:\\Logger.txt');
logger1.save('Error'); //Save message - C:\Logger.txt
let logger2 = new Logger();
logger2.save('Error'); //Save message - C:\Logger\Errors.txt
W powyższym przykładzie nie mamy dostępu do defaultPath, a także do metody setDefaultPath, ponieważ są to lokalne zmienne. Są to szczegóły implementacji, do których nie powinien mieć dostępu (i nie ma) nikt z zewnątrz.

To wszystko co chciałem Ci przekazać w tym artykule. Zapraszam Cię do kolejnych artykułów z serii podstaw programowania w języku JavaScript.

Poprzedni artykuł - Enkapsulacja w JavaScript.
Następny artykuł - Dziedziczenie w JavaScript.
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
Programista C#/.NET. Specjalizuje się w ASP.NET Core, ASP.NET MVC, ASP.NET Web API, Blazor, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Komentarze (1)
Stachu
STACHU, poniedziałek, 12 listopada 2018 17:06
Wydaje mi sie ze bardziej opisujesz enkapsulacje niż abstakcje. Abstrakcja czyli pewne uogólnienie problemu, osiągane jest w innych językach za pomocą klasy abstrakcyjnej lub interfejsu.Jak to sie odbywa w JavaScript?
Dodaj komentarz
© Copyright 2024 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Regulamin. Polityka prywatności. Design by Kazimierz Szpin