trzczy, Damansson ma rację, w tutorialu żadne metody nie są dublowane. Wydaje się, że rzeczywiście nie zrozumiałeś jeszcze dobrze programowanie obiektowego.
AbstractFactory jest interfejsem czyli nie posiada implementacji. Zawiera tylko deklarację metod (deklarację nie definicję bo definicja to implementacja metody).
Każda klasa implementująca interfejs AbstractFactory definiuje metody zadeklarowane w tym interfejsie, ale nie jest to duplikacja. Dzięki temu masz dwie różne implementacje tego samego interfejsu. To znaczy możesz używać obiektu dowolnej z klas pochodnych w dokładnie ten sam sposób, chociaż każda klasa będzie zachowywać się trochę inaczej (czyli korzystasz z polimorfizmu).
Zaleta tego jest taka, że kod który używa obiektu dowolnej z klas implementujących ten interfejs nie musi brać pod uwagę, z jaką klasą konkretnie ma do czynienia. Kod przez to będzie prostszy w zrozumieniu, rozbudowie i testowaniu.
Ktoś u góry podawał już przykład z klasą Storage. Powiedzmy że tworzysz aplikację, która zapisuje jakieś wiadomości do plików lub bazy.
Kod nie był testowany i może zawierać błędy.
<?php
interface StorageInterface
{
public function save($message);
}
class FileStorage implements StorageInterface
{
private $dirPath;
public function __construct($dirPath)
{
$this->dirPath = $dirPath; // ustawiasz katalog(folder) w jakim zapisywać pliki
}
public function save($message)
{
// tu masz kod zapisujący do pliku
}
}
class DbStorage implements StorageInterface
{
public function __construct($dbName, $userName, $passwd, $host)
{
// tu łączymy się z bazą
$this->conn = connect_some_db($dbName, $userName, $passwd, $host);
}
public function save($message)
{
// tu zapisujemy do bazy
}
}
abstract class AbstractRequestHandler
{
protected $storage;
public function __construct(StorageInterface storage)
{
$this->storage = storage;
}
abstract public function handleRequest(Request $request);
}
class ARequestHandler extends AbstractRequestHandler
{
public function handleRequest(Request $request)
{
// tu pobieramy dane z requesta, generujemy wiadomość
// i zapisujemy
$this->storage->save($message);
}
}
class BRequestHandler extends AbstractRequestHandler
{
public function handleRequest(Request $request)
{
// tu pobieramy dane z requesta
// generujemy wiadomość w zupełnie inny sposób niż w klasie ARequestHandler
// i zapisujemy
$this->storage->save($message);
}
}
<?php
// ... tu mamy trochę kodu, tworzymy obiekt Request itp.
$storage = FileStorage('messages/');
$requestHandler = ARequestHandler($storage);
$requestHandler->handleRequest($request);
Ten przykład pokazuje, jak łatwo można zmieniać sposób zapisu wiadomości w aplikacji. Wystarczy zmienić jedną linijkę (stworzyć obiekt klasy DbStorage zamiast FileStorage), a obiekty RequestHandler będą zapisywać wiadomości do bazy danych zamiast do plików. Chcesz zmienić sposób generowania wiadomości? Znowu zmieniasz jedną linijkę ARequestHandler na BRequestHandler.
Obiekty StorageInterface i AbstractRequestHandler możesz tworzyć np. na podstawie pliku konfiguracyjnego przy stracie aplikacji i dalej nie obchodzi Cie z jakiej implementacji korzystasz. Przez to możesz zmieniać zachowanie aplikacji w pliku konfiguracyjnym.
Klasa zajmująca się zapisem do bazy jest interfejsem, ponieważ jedyną wspólną rzeczą dla wszystkich klas zapisujących wiadomości jest to, że aby zapisać wiadomość trzeba wywołać metodą save z jednym argumentem(php 5.x niestety nie pozwala ograniczyć typu argumentu do stringa w deklaracji metody). AbstractRequestHandler jest klasą abstrakcyjną, ponieważ jej klasy pochodne mają wspólny kod (konstruktor).
Zauważ że sposób zapisu i sposób generowania wiadomości zmieniasz niezależnie, dzięki temu że wydzieliliśmy te dwie odpowiedzialności od siebie. Gorszym rozwiązaniem byłoby definiowanie sposobu generowania wiadomości i zapisu w jednej klasie, wtedy moglibyśmy mieć klasy ARequestHandlerFileStorage, ARequestHandlerDbStorage, BRequestHandlerFileStorage itd.
Zanim zacznie się uczyć wzorców projektowych, warto dowiedzieć się trochę na temat ogólnych zasad programowania obiektowego albo kupić dobrą książkę na temat wzorców. W internecie nigdy nie trafiłem na źródła z dobrym wprowadzeniem do programowanie obiektowego, nigdy też nie widziałem w internecie dobrych przykładów.
Jeszcze co do interfejsów:
to pokazuje gdzie mają przewagę nad klasami abstrakcyjnymi przykłady są w javie ale każdy powinien zrozumieć.