piątek, 12 sierpnia 2011

public, protected czy private? Oto jest pytanie!


O tym czym różnią się operatory widoczności można przeczytać tutaj.
Ostatnio zauważyłem dziwną tendencję do używania jedynie dwóch z nich, a mianowicie protected i public. Publiczne są metody (ewentualnie dane), które mają być dostępne na zewnątrz, a wszystko inne jest chronione. W myśl zasady: może kiedyś będę tą klasę rozszerzał. Osobiście nie zgadzam się z takim podejściem. Projektując klasę wiemy, co chcemy aby robiła, a takie wybieganie w przyszłość 'bo może coś się przyda' powoduje niepotrzebny śmietnik.

Moim zdaniem głównymi operatorami, na których powinien się opierać programista projektując klasę, to private i public, a dopiero w dalszej kolejności protected.

Decyzja o tym, którego operatora należy użyć będzie łatwiejsza o ile będzie się pamiętało o kilku rzeczach:
  • Enkapsulacja, czyli atrybuty klas powinny być prywatne. Dlaczego? Krótko i rzeczowo jest to wyjaśnione tutaj.
  • Gdy już mamy atrybuty klasy, trzeba zastanowić się do czego ta klasa będzie wykorzystywana i na tej podstawie należy zdefiniować metody publiczne, czyli te, które będą wykorzystywane przez inne klasy.
  • Jeżeli nie planujesz w obecnej chwili, aby klasa była rozszerzana, to wszystkie metody, które nie są wykorzystywane poza klasą powinny być prywatne. Jeżeli zakładasz, że "może w przyszłości", to również zostaw je jako prywatne. Kod nie jest stałym bytem, może ewoluować, a więc jeżeli zajdzie potrzeba, to zawsze możesz go rozszerzyć lub zmienić.
  • Jeżeli klasa będzie rozszerzana, to metodami chronionymi powinny być jedynie te, które są potrzebne w klasie pochodnej, a nie wszystkie niepubliczne.
  • Jeżeli klasa pochodna powinna mieć dostęp do atrybutów klasy, do których nie ma akcesorów, to nie oznacza, że należy zmienić widoczność atrybutów na protected. To oznacza, że można dodać chronione settery i/lub gettery.
  • Zastanów się trzy razy zanim podejmiesz decyzję o zmianie operatora private na protected w metodach, dziesięć razy jeżeli chcesz to zrobić z atrybutem.
  • Gruntownie przemyśl decyzję o wyciągnieciu metody na zewnątrz, czyli zmianie operatora na public. Rób to tylko wtedy, gdy metoda jest rzeczywiście potrzebna poza klasą.
  • Rzadko istnieje rzeczywista potrzeba zmiany operatora widoczności atrybutu z private na mniej restrykcyjny - protected. Jeszcze rzadziej zachodzi potrzeba upublicznienia atrybutu.

Mam nadzieje, że tych kilka wskazówek się przyda:)

wtorek, 9 sierpnia 2011

Zmienne globalne - a dlaczego nie?


Mimo rozwoju PHP pod kątem OOP, nadal zdarza się niektórym programistom uparcie tworzyć zmienne globalne. Dlaczego? Powód jest prosty i sensowny - w większości aplikacji występują zmienne, które powinny być dostępne w kilku miejscach. Oczywiście można przekazywać ową zmienną z obiektu do obiektu, ale z dwojga złego decydują się na użycie zmiennych globalnych.

Dlaczego takie rozwiązanie nie jest dobre? Abstrahując od faktu, że nie ma zbyt wiele wspólnego z programowaniem obiektowym, to zawsze istnieje możliwość przypadkowego nadpisania jej w innym miejscu w kodzie. Prawdopodobieństwo to zwiększa się, gdy nad kodem pracuje większa ilość programistów.

Więc jakie mamy alternatywy?

Jeżeli zmienna ma być jakąś stałą wartością, niezmienną w całym kodzie i jest typu podstawowego (int, float, bool, string, null), to można skorzystać z metody define() w celu utworzenia wartości stałej (constant).

Co innego, gdy naszą zmienną jest obiekt. W takim wypadku możemy skorzystać z wzorca Singleton, aby mieć pewność, że obiekt będzie posiadał jedną instancję, do której będziemy mogli się dostać w każdym fragmencie kodu poprzez wywołanie statycznej metody zwracającej tą instancję.

Czasami jednak mamy potrzebę przekazywania większej ilości zmiennych różnych typów. Z pomocą przychodzi wzorzec Property. Jest to pewnego rodzaju kontener na zmienne, do których dostęp powinien być możliwy z każdego miejsca w kodzie.

Wybranie dowolnego z tych rozwiązań powinno być jednak gruntownie przemyślane, ponieważ tego typu obiekty utrudniają testowanie (szczególnie klasy implementujące wzorzec singleton). Poza tym nadużywanie któregokolwiek rozwiązania może przyczynić się do zmniejszenia czytelności kodu.