Blog webdeveloperski Patryk yarpo Jar

Wzorzec modułu – dobre praktyki

Autor wiadomości Styczeń 11, 2011

W literaturze spotkać można dwa określenia. Wzorzec modułu [źródło: Mocne strony JavaScript] oraz wzorzec fabryki [źródło: JavaScript dla Webmasterów]. Ja nie widzę zbyt wielkich różnic w samym kodzie, chodzi raczej o ideę, która przyświecała twórcy. We wzorcu modułu stworzyć coś na wzór przestrzeni nazw, komponent całego systemu. W fabryce po prostu funkcję zwracającą obiekt.

Chciałbym zatem tu pokazać kilka dobrych praktyk jakich warto używać przy tworzeniu obiektów z wykorzystaniem wzorca fabryki / modułu. Część z nich jest nieosiągalna w przypadku stosowania np. tworzenia obiektów z prototypu.

1. Pola prywatne

Można tworzyć obiekt tak:

function creator()
{
    var obj = {};
    obj.func1 = function()
    {
         // tu cos robimy;
    }
    obj.func2 = function()
    {
        return obj.func1() + 2;
    }
    return obj;
};

Jednak wtedy możemy zrobić coś takiego:

var o = creator(); // w zmiennej o mamy obiekt z metodami func1 i func2
o.func1 = function()
{
    // kod robiacy cos zupelnie innego niz pierwotna funkcja
}
o.func2(); // wynik zupelnie inny niż pierwotnie!

Tak, łatwo krytykować, ale co zrobić aby tak nie było?

function creator()
{
    function f1()
    {
        // tu cos robimy;
    }
    function f2()
    {
        return f1() + 2;
    }
    return {
        func1 : f1,
        func2 : f2
    };
};

Dzięki temu nadpisując metodę func1, func2 nadal działa tak jak zakładaliśmy.

2. Używanie getterów / setterów

Czym jest getter / setter? Getter to metoda pobierająca wartość jakiejś zmiennej, a setter to metoda ustawiająca wartość zmiennej. Czemu nie odczytywać tego w ten sposób:

obj.a = 12;
alert(obj.a);

Przyczyną jest to, że uzależniamy się od struktury naszego obiektu. Załóżmy, że mamy obiekt do obsługi kwadratu:

function kwadrat()
{
    return {
        pole  : 0,
        bok   : 0,
        obwod : 0
    };
}
var kw = kwadrat();
kw.bok = 10; // ustawilismy dlugosc boku
alert(kw.pole); // nadal 0!!!

A jakbyśmy zrobili to poprawnie:

function kwadrat()
{
    var nPolePowierzchni = 0,
        nDlugoscBoku = 0,
        nDlugoscObwodu = 0;

    function fPole( p )
    {
        if ( !p )
        {
            return nPolePowierzchni;
        }
        nPolePowierzchni = p;
        nDlugoscBoku = Math.sqrt( p );
        nDlugoscObwodu = 4*nDlugoscBoku;
    }
    function fBok( b )
    {
        if ( !b )
        {
            return nDlugoscBoku;
        }
        nDlugoscBoku = b;
        nPolePowierzchni = b*b;
        nDlugoscObwodu = 4*b;
    }
    function fObwod( o )
    {
        if ( !o )
        {
            return nDlugoscObwodu;
        }
        nDlugoscObwodu = o;
        nDlugoscBoku = o/4;
        nPolePowierzchni = nDlugoscBoku * nDlugoscBoku;
    }

    return {
        pole : fPole,
        bok  : fBok,
        obwod : fObwod
    };
};

var kw = kwadrat();
kw.bok(10); // ustawilismy dlugosc boku
alert(kw.pole()); // 100

Później może się okazać, że chcesz jeszcze coś pozmieniać. Gmerasz w "bebechach" ile chcesz. Ale interfejs pozostaje ciągle taki sam dla programisty - użytkownika. Prosty i przejrzysty. Taka zasada odnosi się nie tylko do JS. W każdym języku staraj się tak programować.

3. Konwencja

Coraz częściej spotykana zasada w programowaniu. Zamiast ustawiać wiele zmiennych, zamiast ciągle sprawdzać jak się coś zrobiło w którymś miejscu przyjmij odpowiednią konwencję. W JS nie widać która zmienna skąd pochodzi (zmienne globalne i lokalne wyglądają tak samo). Ale przecież nazwa może ci mówić, co to za zmienna. Oto kilka zasad, których używam ja (nie muszą być najlepszym rozwiązaniem, jednak nawet niedoskonała konwencja jest lepsza od braku jakiejkolwiek):

  • pola prywatne obiektu zapisywane w notacji węgierskiej (możesz oczywiście w inny sposób je oznaczać). Dzięki temu od razu widzę, że to są tego typu zmienne i znam ich zasięg.
  • jeśli używam słówka kluczowego function do tworzenia obiektu, to zawsze stosuję zapisu:
    // funkcji która tu tworzy obiekt do zmiennej (var obj)
    // średnik na koncu - wtedy wiem, ze ta klamra  zamyka obiekt, a nie np. for
    // przypisuje referencje (adres w pamięci)
    var obj = function() {};
  • jeśli obiekt wykorzystuje operator `new' to jego nazwa powinna zaczynać się wielką literą. Jeśli nie - małą. We wzorcu modułu nie trzeba wykorzystywać operatora `new' (choć wywołanie funkcji tworzącej z operatorem new nie powoduje błędu).
  • zmienne lokalne w metodach nazywam wykorzystując notację "podkreśleniową" (nie wiem, jak się to nazywa po polsku:P), np.:
    function przyklad1()
    {
        var zmienna_lokalna;
        zmienna_lokalna = sZmiennaPrywatnaObiektu; // od razu widać skąd pochodzą dane!
    }
  • koduj po polsku albo po angielsku. Staraj się unikać hybryd w stylu:
    var zmienna = my_function(literka, char, ile wyników,  count); 

    taki kod wygląda na bardzo nieprofesjonalny. Dodatkowo ciężko się go czyta. Nie ma nic złego w nazywaniu metod i zmiennych polskimi nazwami. Jednak z głowa!

  • ostatnie, ale nie najmniej ważne: niechże kod sam się komentuje. Ja tu w przykładach często używam zmiennej a, b, c itp. Jednak to dlatego, że ten kod nie ma większego sensu prócz czysto teoretycznego zastosowania pewnej konstrukcji. Kiedy już kodujesz, unikaj zmiennej o nazwie `a' (chyba, że to współczynnik przyspieszenia, albo zmienna przechowująca węzeł DOM <a />).

Faktem jest, że wszystkie opisane tu zasady są przydatne do kodu developerskiego. W przypadku kodu produkcyjnego wcale nie muszą obowiązywać. Warto kompresować kod, co skutecznie zlikwiduje większość opisywanych tu cech kodu:

Warto przeczytać:

Komentarze (0) Trackbacks (0)

Brak komentarzy.


Leave a comment

 

Brak trackbacków.