Interfejs a klasa abstrakcyjna

Interfejsy i klasy abstrakcyjne zostały wprowadzone do php od wersji 5.0. Konstrukcje te znacznie pomagają w uporządkowaniu struktury aplikacji, pozwalają na zachowanie kontroli typów, integralność oraz logiczną budowę aplikacji.

Dzięki wdrożeniu tych konstrukcji do aplikacji możemy w lepszy i logiczniejszy sposób odwzorować rzeczywistość a zarazem ustrzec się potencjalnych błędów, poza tym zyskujemy większą kontrolę nad modelowaną obiektową rzeczywistością.

Klasy abstrakcyjne
Klasy abstrakcyjne służą do modelowania rzeczywistości, którą chcemy przenieść do logiki swojej aplikacji. Klasa abstrakcyjna definiuje w dużej ogólności pewien podstawowy model i zachowanie obiektu.

Powiedzmy, że chcemy chcemy stworzyć wirtualne zoo. W zoo znajdować się będą różnorakie zwierzęta np: małpy, lisy, wiewiórki, motyle, pszczoły, żaby, jaszczurki.

Każde zwierzę opisywane jest przez podstawowe atrybuty jak: wiek, rozmiar oraz cechy taki jak: rodzenie, chodzenie, jedzenie.

Tworzymy zatem podstawową klasę abstrakcyjną 'Zwierze’ zawierającą abstrakcyjne metody: born, go, eat:

abstract class Animal {

	protected $age;
	protected $width;
	protected $height;

	abstract protected function born();
	abstract protected function go();
	abstract protected function eat();

	protected function setAge( $years ) {
		$this->age = $years;
	}

	protected function setSize( $width, $height ) {
		$this->width = $width;
		$this->height = $height;
	}
}

Dzięki użyciu klasy abstrakcyjnej mamy pewność, że nikt nie stworzy obiektu klasy 'Zwierze’. Z logicznego punktu jest to niemożliwe gdyż nie ma zwierzęcia 'Zwierze’ – taki byt w rzeczywistości nie istnieje gdyż jest to zbyt ogólne pojęcie.

Dodatkowo zadeklarowaliśmy metody born, go, eat jako abstrakcyjne co wymusi ich implementacje w klasach dziedziczących – to też jest jak najbardziej logiczne gdyż nie ma zwierzęcia, które nie może wykonywać tych czynności. Metody te deklarujemy jako abstrakcyjne gdyż nie znając zwierzęcia nie wiemy jeszcze jak je zaimplementować. Metody abstrakcyjne muszą być puste.

Zadeklarowaliśmy również podstawowe atrybuty ($age, $width, $height), które każde zwierze posiadać musi, oraz settery które je ustawiają. Przy setterach ustawiamy specyfikator dostępu protected, dzięki temu będą mogły być wywoływane jedynie z poziomu metod klas dziedziczących. Nie ustawiamy ich jako abstrakcyjnych gdyż ich implementacja w klasie 'Animal’ jest wystarczająca i klasy potomne będą z nich korzystać.

Tworzymy teraz klasę konkretnego zwierzęcia np. małpy:

require_once 'animal.php';

class Monkey extends Animal {

	public function born() {/*@TODO*/}
	public function go() {/*@TODO*/}
	public function eat() {/*@TODO*/}

	public function __construct( $age, $size ) {
		$this->setAge( $age );
		$this->setSize( $size[0], $size[1] );
	}
}

$monkey1 = new Monkey( 2, array( 100, 20 ) );
var_dump( $monkey1 );

Musi ona posiadać metody abstrakcyjne, w ciele klasy 'Monkey’, powinny one przybrać docelową formę. Jak widać nie ma setterów, jest za to konstruktor przyjmujący parametry obiektu i wywołuje odpowiednie settery z klasy bazowej 'Animal’.

Interfejs
Klasa abstrakcyjna jest dość mocno związana logicznie z obiektami z niej dziedziczącymi. Widać jasno, że małpa i lis są integralnie związane z definicją zwierzęcia. Interfejs natomiast jedynie narzuca klasie jakie metody powinna posiadać, interface definiuje pewne właściwości, które klasa musi spełniać. Sam w sobie nie definiuje logicznej zależności pomiędzy sobą a klasą go implementującą, definiuje natomiast powiązanie pomiędzy wszystkimi klasami go implementującymi. Agreguje klasy obiektów na których można wykonać pewne operacje.

Kontynuując przykład zoo… załóżmy, że zoo może sprzedawać i kupować zwierzęta zatem możemy stworzyć interface 'Trade’:

interface Trade {
	public function sell();
	public function buy();
}

Dodatkowo, zwierzęta podlegają ubezpieczeniom zatem tworzymy interface 'Insurance’:

interface Insurance {
	public function make();
	public function withdrawn();
}

Jedna klasa może implementować wiele interfejsów, w przykładzie zoo 'Animal’ będzie implementował zarówno 'Trade’, jak i 'Insurance’. Jak widać kolejne interfejsy nie są ze sobą związane jednak wpływają na zachowanie się obiektu zwierzęcia.

class Monkey extends Animal implements Trade, Insurance {
	public function born() {/*@TODO*/}
	public function go() {/*@TODO*/}
	public function eat() {/*@TODO*/}
	
	public function sell() {/*@TODO*/}
	public function buy() {/*@TODO*/}
	
	public function make() {/*@TODO*/}
	public function withdrawn() {/*@TODO*/}
	

	public function __construct( $age, $size ) {
		$this->setAge( $age );
		$this->setSize( $size[0], $size[1] );
	}
}

Ale przecież w zoo są nie tylko zwierzęta ale także budynki i ludzie. Budynki mogą być odprzedawane a ludzie ubezpieczani zatem klasy reprezentujące te obiekty także powinny implementować te interfejsy.

Klasa 'People’ powinna implementować 'Insurance’ a klasa 'Building’ interfejs 'Trade’.

class People implements Insurance {
	public function make() {/*@TODO*/}
	public function withdrawn() {/*@TODO*/}
}
class Building implements Trade {
	public function sell() {/*@TODO*/}
	public function buy() {/*@TODO*/}
}

Widzimy zatem, że klasy reprezentujące zupełnie różne obiekty (zwierzęta, budynki) w pewnym zakresie zachowują się tak podobnie (można je kupić i sprzedać) zatem implementują interface 'Trade’.

Dzięki zapisowi tych zależności nasza aplikacja nabiera logicznego kształtu a dodatkowo dzięki parserowi zyskujemy darmową walidację, gdyż w przypadku braku metody z interfejsu php zwróci błąd – zatem nie zapomnimy o jej implementacji.

VIM – podstawowe komendy

Ktoś może pomyśleć – „po co mi znajomość VIMa, przecież jest milion przyjaźniejszych dla użytkownika edytorów”. Zgodzę się, po części – jest wiele UNIX-owych edytorów tekstu posiadających interface dużo przyjaźniejszy jednak żaden z nich nie ma takich dużych możliwości jak stary poczciwy VIM, nie znam innego edytora, który z równie sprawnie i szybko edytuje pliki 200 megowe. Zresztą na niektórych serwerach (wierzcie mi, że są takie) VIM jest jedynym dostępnym edytorem tekstu.

Jako, że kiedyś sam szukałem prostego manuala z podstawowymi komedami VIMa to może komuś się przyda:

poruszanie się po dokumencie
+ – przejście do następnej linii
– – przejście do poprzedniej linii
0 – przejście do początku linii
^ – przejście do pierwszego znaku nie będącego znakiem białym w linii
$ – przejście na koniec linii
n| – przejście do kolumny n linii
} – przejście do następnego paragrafu
{ – przejście do poprzedniego paragrafu
% – przejście do otwarcia / zamknięcia nawiasu (),[],<>,{}
G – przejście na koniec dokumentu
nG – przejście do linii <n>

zapisywanie
:x lub :wq – zapisywanie pliku i wyjście
:q! – wyjście bez zapisania zmian
:w plik – zapisanie w nowym pliku „plik”

wyszukiwanie
/ STRING – szukanie do przodu
? STRING – szukanie do tyłu
n – przejście do następnego znalezionego elementu
SHIFT+n przejście do poprzedniego znalezionego elementu

kasowanie tekstu
x – kasowanie bieżącego znaku
nx – kasowanie znaków
dw – kasowanie bieżącego wyrazu
dd – kasowanie bieżącej linii
ndd – kasowanie <n> linii
D – kasowanie znaków od kursora do końca bieżącej lini
dG – kasowanie wszystkiego od kursora do końca dokumentu

edycja tekstu
o – wstawienie nowej linii poniżej bieżącej
O – wstawienie nowej linii powyżej bieżącej
i – rozpoczęcie edycji przed kursorem
I – rozpoczęcie edycji na początku bieżącej linii
a – rozpoczęcie edycji po kursorze
A – rozpoczęcie edycji na końcu bieżącej linii
cw – zastąpienie wyrazu (bieżący wyraz się kasuje, kursor ustawia się na jego początku)
cc – zastąpienie linii (bieżąca linia się kasuje, kursor ustawia się na jej początku)

kopiowanie i wstawianie
yw – kopiuj do schowka bieżący wyraz
yb – kopiuj do schowka poprzedni wyraz
Y – kopiuj do schowka bieżącą linię
nY – kopiuj następne <n> linii
p – wklej skopiowany tekst za kursorem
P – wklej skopiowany tekst przed kursorem

inne
u – cofnięcie ostatniej zmiany
U – cofnięcie wszystkich zmian w bieżącej linii
. – powtórzenie ostatniej komendy
SHIFT+# – wyszukiwanie wyrażeń pasujących do zaznaczonego
SHIFT+% – przejście do kolejnego nawiasu () lub {}
~ – zmiana litery z małej na dużą i na odwrót

zastępowanie
Można używać wyrażeń regularnych PERL- kompatybilnych

zastąpienie stringu OLD stringiem NEW
:s/OLD/NEW – pierwszego wystąpienia w bieżącej linii
:s/OLD/NEW/g – każdego wystąpienia w linii
:#,#s/OLD/NEW/g – pomiędzy liniami # i #
:%s/OLD/NEW/g – w całym dokumencie
:%s/\([0-9]\+\) OLD/\1 NEW/g – w całym dokumencie z użyciem backreferencji (trzeba poprzez „\” wyescapować znaki specjalne, następnie poprzez „\1” wstawić wyciągnięte dane)

praca z danymi zewnętrznymi
Vim umożliwia wywołanie dowolnej komendy z poziomu edytora, można także odczytywać efekt jej działania

:! komenda – wywołanie 'komenda’ w shellu i wyświetlenie jej wyniku, komenda może być każde polecenie unixowe
:r ! komenda – wywołanie 'komenda’ w shellu i wczytanie wyniku jej działania do edytora
:r ! last | grep user – na wywoływanych komendach można robić dowolne operacje przed wczytaniem do edytora
:r textfile – wczytanie źródła pliku 'textfile’ do edytora
:r ! w3m http://en.wikipedia.org/wiki/Vi -dump – wczytanie do edytora zawartości strony internetowej

Praca z zakładkami
:tabs – wyświetlenie informacjie o aktualnie otwartych zakładkach
:tabnew – otwarcie pustej zakładki
:tabnew FILE – otwarcie pliku FILE w nowej zakładce
:tabf FILE – otwarcie pliku w nowej zakładce
:tabn – przejście do następnej zakładki
gt – przejście do następnej zakładki (działa w trybie NORMAL)
gT – przejście do poprzedniej zakładki (działa w trybie NORMAL)
n gt – przejście do zakładki o numerze n (działa w trybie NORMAL)
n gT – cofnięcie się do zakładki znajdującej się w odległości n od aktualnej (działa w trybie NORMAL)
:tabp – przejście do poprzedniej zakładki
:tabl – przejście do ostatniej zakładki
:tabc – zamknięcie aktualnej zakładki, gdy jest jedna karta, to nie będzie zamknięta
:tabo – zamknięcie wszystkich zakładek oprócz tej która jest aktualnie używana
:tabd KOMENDA – wykonuje komendę na wszystkich otwartych zakładkach

Polecam rewelacyjny VIM Tutorial.

Możliwe problemy i ich rozwiązania

  • Jeżeli przy wklejaniu do konsoli kodu z tabulacjami/spacjami tworzą się niechciane wcięcia należy użyć polecenia „:set paste” następnie wkleić kod i ponownie ustawić „:set nopaste”, więcej o wklejaniu na w tym temacie stackoverflow.

Zobacz też A vim Tutorial and Primer.