2012-03-07 18 views
5

Uno può fare la stessa cosa utilizzando strumenti diversi. Così ho negli esempi qui sotto.PHP OOP: interfaccia vs approccio non-interfaccia - esempi

Uno mostra l'uso dell'interfaccia/polimorfismo (fonte: nettuts - Penso). Un'altra interazione di classe diretta (la mia) - che mostra anche qualche polimorfismo (tramite call_tool()).

Mi diresti, quale consideri un modo migliore.

Quale è più sicuro, più stabile, a prova di manomissione, a prova di futuro (lo sviluppo del codice AFA è interessato).

Si prega di esaminare la portata/la visibilità utilizzata in entrambi.

Le vostre raccomandazioni generali, come la migliore pratica di codifica.

INTERFACCIA:

 
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 INTERFACCIA

 
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(); 

codice MikeSW (se ho capito bene)

 
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); 

risposta

2

Ahem, i tuoi approcci hanno alcuni difetti, non importa quale versione . Per prima cosa, poly_base_Article espone i campi che interrompono l'incapsulamento e sconfigge in qualche modo lo scopo dell'uso di OOP.

Successivamente, si esegue un'iniezione fine tramite il parametro $ _GET. Il modo corretto di fare la classe dovrebbe essere così

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); 
} 
} 

Il metodo di scrittura non sembra essere richiesto, però, basta solo far sapere lo scrittore di scrivere direttamente l'oggetto.

Il * call_tool metodo * dovrebbe appartenere a un servizio o come un metodo factory per creare un'istanza di poly_writer_Writer (btw, è necessario modificare la denominazione delle classi e l'interfaccia a qualcosa di più naturale), qualcosa di simile

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); 

Quale è più sicuro, più stabile, resistente alla manomissione, a prova di futuro (lo sviluppo del codice AFA è interessato).

Ciò dipende solo dalle capacità e dalla disciplina dello sviluppatore. In questo caso particualr, il codice che ho scritto è il più sicuro, a prova di manomissione resistente e futuro: P

Aggiornamento Anzi, ho dimenticato di mettere getter nel poly_base_Article, li ho aggiunto ora. Dato che stai facendo serializzazione, l'articolo non dovrebbe saperlo, poiché non è la sua responsabilità (fa parte del livello infrastruttura) quindi il metodo di scrittura non è affatto necessario, ma questo è un caso specifico qui (nel tutto dipende sul contesto).

WriterFactory è fondamentalmente il modello di fabbrica che crea un'istanza dello scrittore e restituisce un'astrazione - questo è il polimorfismo in cui l'interfaccia è utile.Questo approccio semplifica molto l'aggiunta di nuove implementazioni dell'interfaccia e anche la protezione dall'iniezione di codice. L'opzione consiste nel controllare che siano consentiti solo i valori validi di $ type. Potresti convalidare il tipo $ in altri posti, ma questo è l'unico posto che dovrebbe gestire tutto ciò che riguarda la creazione di scrittori. Anche se si desidera eseguire la convalida al di fuori di esso, è sufficiente creare un metodo statico in WriterFactory che restituirà true/false e use than.

Le interfacce sono una moda ... l'uso delle interfacce è come dovrebbe essere fatto OOP. È una buona pratica programmare contro un'astrazione e le interfacce sono l'astrazione "migliore". Per dirla senza mezzi termini: se le interfacce sono una moda passeggera, allora OOP è una moda passeggera.

Informazioni sul secondo esempio, ben il primo troppo, il metodo che crea lo scrittore non dovrebbe essere lì, in primo luogo, come si accoppia la creazione dello scrittore per l'articolo e quelle 2 hanno praticamente nulla in comune. È una rottura dell'SRP (Single Responsability Principle).

In questo caso particolare, una volta che si sta creando la factory di creazione in una classe separata, non ci si preoccupa delle interfacce, tuttavia perché l'utilizzo è molto semplice qui e si sta utilizzando PHP o un tipo di lingua. Se si passasse allo scrittore come una dipendenza, questo aiuterà a passare l'interfaccia e non un'implementazione reale (come hai fatto nel primo esempio). È molto utile sapere che tipo stai passando.

Anche in un linguaggio come C#, avresti un tipo di ritorno e quindi, come utilizzo ottimale, lo restituiresti come tipo di interfaccia (C# supporta tipi dinamici che diciamo si comportano un po 'come in PHP, quindi puoi restituisce dinamica e non cura, ma ciò comporta una penalizzazione delle prestazioni e se il tipo restituito non ha il metodo invocato genererà un'eccezione)

+0

$ _GET - questo non faceva parte di q. ;), quindi non ho prestato molta attenzione. Nel codice dal vivo sarebbe guardato correttamente da ogni angolazione. Ma hai ragione, non dovrei lasciarlo passare, anche se era fuori q. scopo. – Jeffz

+0

se si rendono private le proprietà poly_base_Article, in che modo ad es. poly_writer_xmlWriter li accede? non esiste alcuna relazione tra di loro – Jeffz

+0

WriterFactory - non si tratta solo di creare oggetti aggiuntivi senza molte funzionalità aggiunte da esso? – Jeffz

1

Vorrei iniziare il tutto raccomandando this video e altri video da serie .

Ci sono due condizioni che renderebbero interfacce preferibile:

  • si sta lavorando in una squadra
  • lungo termine del progetto

uso di interfacce agisce come un'altra serie di documenti, quando si necessità di espandere la funzionalità del codice base. Quindi viene utilizzato anche lo principle of least astonishment.

In un piccolissimo progetto & non è possibile utilizzare le interfacce.

+0

Uso le interfacce ovunque sia necessario per astrarre qualcosa indipendentemente dalle dimensioni della complessità del progetto – MikeSW

Problemi correlati