2012-03-07 10 views
5

Można dokonać tego samego przy użyciu różnych narzędzi. Więc mam I w przykładach poniżej.PHP OOP: interfejs a podejście nieinterfejsowe - przykłady

Jedna pokazuje użycie interfejsu/polimorfizmu (źródło: nettuts - myślę). Kolejne proste interakcje klasowe (moje) - które również wykazują pewien polimorfizm (przez call_tool()).

Czy możesz mi powiedzieć, co uważasz za lepszy sposób.

Co jest bezpieczniejsze, bardziej stabilne, odporne na manipulacje, przyszłościowe (dotyczy rozwoju kodu).

Prosimy o sprawdzenie zakresu/widoczności stosowanych w obu.

Twoje ogólne zalecenia, które najlepiej sprawdzają się w kodowaniu.

interfejs:

 
class poly_base_Article { 

    public $title; 
    public $author; 
    public $date; 
    public $category; 

    public function __construct($title, $author, $date, $category = 0, $type = 'json') { 
     $this->title = $title; 
     $this->author = $author; 
     $this->date = $date; 
     $this->category = $category; 

     $this->type = $type; 
    } 

    public function call_tool() { 
     $class = 'poly_writer_' . $this->type . 'Writer'; 
     if (class_exists($class)) { 
      return new $class; 
     } else { 
      throw new Exception("unsupported format: " . $this->type); 
     } 
    } 

    public function write(poly_writer_Writer $writer) { 
     return $writer->write($this); 
    } 

} 

interface poly_writer_Writer { 

    public function write(poly_base_Article $obj); 
} 

class poly_writer_xmlWriter implements poly_writer_Writer { 

    public function write(poly_base_Article $obj) { 
     $ret = ''; 
     $ret .= '' . $obj->title . ''; 
     $ret .= '' . $obj->author . ''; 
     $ret .= '' . $obj->date . ''; 
     $ret .= '' . $obj->category . ''; 
     $ret .= ''; 
     return $ret; 
    } 

} 

class poly_writer_jsonWriter implements poly_writer_Writer { 

    public function write(poly_base_Article $obj) { 
     $array = array('article' => $obj); 
     return json_encode($array); 
    } 

} 

$article = new poly_base_Article('Polymorphism', 'Steve', time(), 0, $_GET['format']); 
echo $article->write($article->call_tool()); 

NON-Interface

 
class npoly_base_Article { 

    public $title; 
    public $author; 
    public $date; 
    public $category; 

    public function __construct($title, $author, $date, $category = 0, $type = 'json') { 
     $this->title = $title; 
     $this->author = $author; 
     $this->date = $date; 
     $this->category = $category; 
     $this->type = $type; //encoding type - default:json 
    } 

    public function call_tool() { 
     //call tool function if exist 
     $class = 'npoly_writer_' . $this->type . 'Writer'; 
     if (class_exists($class)) { 
      $cls = new $class; 
      return $cls->write($this); 
     } else { 
      throw new Exception("unsupported format: " . $this->type); 
     } 
    } 

} 

class npoly_writer_jsonWriter { 

    public function write(npoly_base_Article $obj) { 
     $array = array('article' => $obj); 
     return json_encode($array); 
    } 

} 

class npoly_writer_xmlWriter { 

    public function write(poly_base_Article $obj) { 
     $ret = ''; 
     $ret .= '' . $obj->title . ''; 
     $ret .= '' . $obj->author . ''; 
     $ret .= '' . $obj->date . ''; 
     $ret .= '' . $obj->category . ''; 
     $ret .= ''; 
     return $ret; 
    } 

} 

$article = new npoly_base_Article('nPolymorphism', 'Steve', time(), 0, $_GET['format']); 
echo$article->call_tool(); 

kod MikeSW (jeśli mam rację)

 
class poly_base_Article { 

    private $title; 
    private $author; 
    private $date; 
    private $category; 

    public function __construct($title, $author, $date, $category = 0) { 
     $this->title = $title; 
     $this->author = $author; 
     $this->date = $date; 
     $this->category = $category; 
    } 

    public function setTitle($title) { 
     return $this->title = $title; 
    } 

    public function getTitle() { 
     return $this->title; 
    } 

    public function getAuthor() { 
     return $this->author; 
    } 

    public function getDate() { 
     return $this->date; 
    } 

    public function getCategory() { 
     return $this->category; 
    } 


} 

interface poly_writer_Writer { 

    public function write(poly_base_Article $obj); 
} 

class poly_writer_xmlWriter implements poly_writer_Writer { 

    public function write(poly_base_Article $obj) { 

     $ret = ''; 
     $ret .= '' . $obj->getTitle() . ''; 
     $ret .= '' . $obj->getAuthor() . ''; 
     $ret .= '' . $obj->getDate() . ''; 
     $ret .= '' . $obj->getCategory() . ''; 
     $ret .= ''; 
     return $ret; 
    } 

} 

class poly_writer_jsonWriter implements poly_writer_Writer { 

    public function write(poly_base_Article $obj) { 
     //array replacement 
     //$obj_array = array('title' => $obj->getTitle(), 'author' => $obj->getAuthor(), 'date' => $obj->getDate(), 'category' => $obj->getCategory()); 
     //$array = array('article' => $obj_array); 

     $array = array('article' => $obj); //$obj arrives empty 
     return json_encode($array); 
    } 

} 

class WriterFactory { 

    public static function GetWriter($type='json') { 
     switch ($type) { 
      case 'json': 
      case 'xml': $class = 'poly_writer_' . $type . 'Writer'; 
       return new $class; 
       break; 
      default: throw new Exception("unsupported format: " . $type); 
     } 
    } 

} 

$article = new poly_base_Article('nPolymorphism', 'Steve', time(), 0); 
$writer=WriterFactory::GetWriter($_GET['format']); 

echo $writer->write($article); 

Odpowiedz

2

Hm, twoja podejścia mają pewne wady bez względu na wersję . Po pierwsze, poly_base_Article eksponuje pola, które przerywają enkapsulację i w inny sposób pokonuje cel użycia OOP w pierwszej kolejności.

Następnie należy wykonać drobny zastrzyk za pomocą parametru $ _GET. Właściwym sposobem na klasę powinny być tak

class poly_base_Article { 

private $title; 
private $author; 
private $date; 
private $category; 

public function __construct($title, $author, $date, $category = 0) { 
    $this->title = $title; 
    $this->author = $author; 
    $this->date = $date; 
    $this->category = $category; 

} 

public function getTitle() { return $this->title;} 
//...other getters defined here... 

    public function AsArray() 
    { 
      return (array) $this; 
    } 

//this could be removed 
public function write(poly_writer_Writer $writer) { 
    return $writer->write($this); 
} 
} 

zapisu metoda nie wydaje się być konieczne, choć, po prostu powiedzieć pisarz pisać obiektu bezpośrednio.

* przy call_tool * metoda powinna należeć do usługi lub jako metoda fabryki, aby utworzyć instancję poly_writer_Writer (btw, należy zmienić nazewnictwo klas i interfejsu na coś bardziej naturalnego), coś w tym

class WriterFactory 
{ 
    public static function GetWriter($type='json') 
     { 
     switch($type) 
     { 
      case 'json' 
      case 'xml': $class= 'poly_writer_' . $type . 'Writer'; 
      return new $class; 
       break; 
      default: throw new Exception("unsupported format: " . $type); 
      } 
     } 
} 


    $article = new poly_base_Article('nPolymorphism', 'Steve', time(), 0); 
    $writer=WriterFactory::GetWriter(, $_GET['format']); 
echo $writer->write($article); 

Co jest bezpieczniejsze, bardziej stabilne, odporne na manipulacje, przyszłościowe (dotyczy rozwoju kodu).

To zależy tylko od umiejętności i dyscypliny programisty. W tym particualr przypadku kod Pisałem jest bezpieczniejsze, plombowania i odpornego na przyszłość: P

Aktualizacja Rzeczywiście, zapomniałem umieścić pobierające w poly_base_Article, dodałem je teraz. Ponieważ robisz serializację, artykuł nie powinien o tym wiedzieć, ponieważ nie jest to jego responsability (jest to część warstwy infrastruktury), więc metoda zapisu nie jest wymagana, ale to jest konkretny przypadek tutaj (we wszystkim zależy w kontekście).

WriterFactory to po prostu fabryczny wzorzec, który tworzy instancję piszącego i zwraca abstrakcję abstrakcyjną - to polimorfizm, w którym interfejs jest użyteczny.Takie podejście bardzo ułatwia dodawanie nowych implementacji interfejsu, a także chroni przed wtryskiem kodu. Przełącznik polega na sprawdzeniu, czy dozwolone są tylko prawidłowe wartości typu $. Możesz potwierdzić typ $ w innych miejscach, ale jest to jedyne miejsce, które powinno zajmować się wszystkim, co wiąże się z tworzeniem pisarzy. Nawet jeśli chcesz zatwierdzić poza nim, po prostu stwórz metodę statyczną w WriterFactory, która zwróci true/false i użyje niż.

O interfejsach będących modą ... używanie interfejsów to sposób programowania OOP. Najlepszą praktyką jest programowanie przeciwko abstrakcji, a interfejsy są "najlepszą" abstrakcją. Mówiąc wprost: jeśli interfejsy to moda, to OOP jest modą.

O twoim drugim przykładzie, no i na początku, metoda, która tworzy pisarza, nie powinna być tam na pierwszym miejscu, ponieważ łączy twórcę z artykułem, a te dwa nie mają ze sobą nic wspólnego. Jest to łamanie zasady SRP (Single Responsability Principle).

W tym konkretnym przypadku, gdy robisz fabrykę tworzenia w osobnej klasie, to prawie nie interesują Cię interfejsy, jednak ponieważ użycie jest tu bardzo uproszczone i używasz PHP lub luźno wpisz język. Jeśli przekażesz program piszący jako zależność, to pomoże to przejść przez interfejs, a nie rzeczywistą implementację (tak jak w pierwszym przykładzie). Bardzo dobrze jest wiedzieć, jaki typ przechodzisz.

Również w języku takim jak C#, miałbyś typ zwrotny, a następnie, jako optymalne użycie, zwróciłbyś go jako typ interfejsu (C# obsługuje typy dynamiczne, np. Zachowuj się trochę jak w PHP, dzięki czemu możesz zwracaj dynamiczne i nie przejmuj się, ale jest to związane z karą wykonania, a jeśli zwracany typ nie ma wywoływanej metody, to wyrzuci wyjątek)

+0

$ _GET - to naprawdę nie było częścią q. ;), więc nie zwracałem na to uwagi. W żywym kodzie byłby właściwie oglądany pod każdym kątem. Ale masz rację, nie powinienem pozwolić, żeby to przeszło, nawet jeśli to było z q. zakres. – Jeffz

+0

jeśli właściwości poly_base_Article są prywatne, jak można np. poly_writer_xmlWriter dostęp do nich? nie ma między nimi związku – Jeffz

+0

WriterFactory - czy nie jest to tylko tworzenie dodatkowego obiektu bez dodawania przez niego dużej funkcjonalności? – Jeffz

1

Zacznę od wszystkiego polecając this video i inne filmy z serii .

Istnieją dwa warunki, które sprawiają, że interfejsy preferowane:

  • pracujesz w zespole
  • długoterminowy projekt

Zastosowanie interfejsów działa jak inny zestaw dokumentacji, kiedy trzeba rozszerzyć funkcjonalność twojej bazy kodów. Używa się wtedy również principle of least astonishment.

W bardzo małym, szybkim projekcie & nie ma sensu używanie interfejsów.

+0

Używam interfejsów wszędzie tam, gdzie muszę coś abstrakcjonować, niezależnie od wielkości złożoności projektu – MikeSW