2010-08-01 7 views
7

Uno dei principali principi di progettazione è il programma per un'interfaccia e non un'implementazione. Ciò è possibile anche in php o in qualsiasi altra lingua debolmente tipizzata.Programma su un'interfaccia non un'implementazione in php

EDIT:

io forse non ha ancora scritto la questione nel modo più chiaro come avrei dovuto. Non voglio dire che php non posso usare le interfacce - può farlo obvisouly. Voglio dire, il principio di progettazione "programma a un'interfaccia e non a un'implementazione" diventa ridondante in lingue debolmente tipizzate.

+0

Vedere il mio post modificato. Non riesco a capire perché sarebbe "ridondante" – NullUserException

risposta

4

Sì. Definire l'interfaccia:

interface iTemplate 
{ 
    public function setVariable($name, $var); 
    public function getHtml($template); 
} 

E implementarlo:

// Implement the interface 
class Template implements iTemplate 
{ 
    private $vars = array(); 

    public function setVariable($name, $var) 
    { 
     $this->vars[$name] = $var; 
    } 

    public function getHtml($template) 
    { 
     foreach($this->vars as $name => $value) { 
      $template = str_replace('{' . $name . '}', $value, $template); 
     } 

     return $template; 
    } 
} 

manuale di PHP su interfacce: http://php.net/manual/en/language.oop5.interfaces.php

Non so il motivo per cui non sarebbe possibile avere interfacce solo perché il il linguaggio è debolmente tipizzato.


EDIT: Il punto (più o meno) di avere un interfaccia è in modo da poter riutilizzare il codice indipendentemente dalla classe che implementa l'interfaccia effettivamente detto.

dire il vostro programma utilizza un'interfaccia Set, che ha metodi addItem(), removeItem() e . Con le interfacce, sai che sarai in grado di chiamare uno di questi 3 metodi indipendentemente dall'implementazione Set sottostante, sia essa HashSet, TreeSet o qualsiasi altra cosa.

Questo non cambia se si utilizza un linguaggio tipizzato debolmente; puoi ancora scrivere codice come se stessi usando una lingua fortemente tipizzata. So di non aver detto questa spiegazione molto bene, ma spero che tu abbia avuto l'idea.

0

php ha interfaces ed è possibile programmarli. Perché non dovresti essere in grado di farlo?

Programmazione su un'interfaccia significa che è sufficiente utilizzare la funzionalità offerta dall'interfaccia e non fare affidamento sui dettagli di implementazione né utilizzare altre funzionalità offerte dall'implementazione e semplicemente lo si conosce, perché l'implementazione potrebbe cambiare (l'interfaccia non dovrebbe).

+0

Bene, l'intero punto del principio sembra diventare inutile quando non si usano i tipi. Certo, puoi usare le interfacce in php, ovviamente non sto contestando, sto dicendo che il principio non è efficace quando non puoi usare il tipo di oggetto. Ad esempio, in un linguaggio fortemente tipografico che useresti: Type t = new ConcreteType - in php devi semplicemente dire $ t = new ConcreteType. Sure ConcreteType implementerà l'interfaccia ma il codice di installazione non ne sa nulla. Forse ho frainteso il principio. – David

+0

@David Di sicuro perdono alcuni dei loro vantaggi in un linguaggio debolmente digitato, ma sono comunque utili se usati correttamente. – NullUserException

+0

Ma il principio è inteso in modo che "Una volta che dipendi solo dalle interfacce, sei disaccoppiato dall'implementazione" E Gama, ma in un linguaggio debolmente tipizzato stai semplicemente usando la classe concreta durante l'istanziazione. Non riesco a vedere come si applica il principio qui. Probabilmente sono solo stupido, ma per qualche motivo mi fa rabbia. – David

0

Dipende da cosa intendi per "interfaccia" e "implementazione". Questi sono termini sciolti i cui significati possono cambiare a seconda del contesto.

PHP5 contiene OOP costruisce simile a Java e C#, come ad esempio oggetti come riferimenti, classi, classi astratte e interfacce. Contiene anche suggerimenti sui tipi per i parametri del metodo. Questi strumenti potrebbero essere, e sono stati, usati per costruire "un'interfaccia" per qualcosa.

0

L'obiettivo finale è disporre di un'interfaccia su cui ogni componente è d'accordo.

Quindi, se, per esempio, stavo costruendo un sito JavaScript che era stato fatto interamente in una implementazione MVC (non-Rails/PHP) vecchia e completamente in AJAX, mi sarei assicurato che ognuno di i componenti implementavano la stessa interfaccia per l'osservazione.

In ogni modello/vista/controller, potrei chiamare il mio metodo "subscribe" qualcosa di completamente diverso. Oppure, potrei implementare un'interfaccia standard per ciascuno.

modo che io possa avere una "(event_type, subscribing_class) .Register" metodo pubblico implementato in ogni singolo componente che ci si poteva aspettare di essere chiamato.

Analogamente, posso avere un "(event_type, dati) .Update" metodo pubblico implementato in ogni singolo componente che potrebbe essere previsto per essere chiamato.

Il .Register e .Update sono l'interfaccia per la mia comunicazione Observer. All'interno delle mie classi, ognuno potrebbe avere un metodo ".Subscribe (publisher, event_type, self_reference)". Questo metodo potrebbe essere proprio:

Class.Subscribe = function (publisher, event_type) { 
    var self_reference = this; 
    publisher.Register(event_type, self_reference); 
}; 

Ogni potrebbe avere un metodo .Notify interna:

Class.Notify = function (type, data) { 
    var subscribers = this.subscribers[type], 
     i = 0, l = subscribers.length; 

    for (; i < l; i++) { subscribers[i].Update(type, data); } 
}; 

Perché ho accettato che tutti i miei interfaccia di comunicazione sta andando a comportarsi in questo modo, non importa come sono i miei interni.

Il mio modello può continuare ad essere ignaro mio punto di vista, e la mia View può continuare ad essere ignaro mio controller.

Il .Notify e .Iscriviti non hanno bisogno di essere implementato in questo modo - non sono una parte dell'interfaccia accessibile al pubblico. Potrebbero essere tutto ciò che voglio.

.Iscriviti potrebbe prendere una serie di editori e spingerlo attraverso un ciclo for, per iscriversi a più punti di dati. Oppure prendi una serie di {"pub": x, "tipo": y} letterali oggetto, e chiama il metodo .Register di ciascuno, in modo che tu possa ottenere TUTTO il bootstrap di quella Classe con una chiamata di funzione.

Lo stesso vale per l'app di riproduzione audio. Non mi interessa quali proprietà pubbliche MusicPlayer condivide. So che usa .Play(), .Pause(), .Stop(), .Load (traccia).

Se mi assicuro di utilizzare SOLO i metodi di interfaccia pubblici concordati, il programma funzionerà. Perché?

perché il ragazzo che lavora su MusicPlayer potrebbe cambiare i meccanismi interni di MusicPlayer. Potrebbe riscriverli completamente. Forse c'è un ._ metodo precacheSong (traccia). Ma cosa succede se viene sostituito con. _cueTrack (traccia) lungo la strada?

stai usando solo widget di qualche amico, e un giorno di widget di crash, perché si erano estendendola o attuazione sulla base di metodi non-Interface o dati non interfaccia, che è accaduto a cambiare a partire dal v1.2.1

Quindi, anche in lingue lente, l'interfaccia è importante. Ti danno una mappa di come puoi aspettarti di chiamare QUALSIASI componente che ci si aspetta abbia quella funzionalità - e indipendentemente da come funzionano gli interni di quel componente, gli input e gli output saranno esattamente gli stessi (sebbene più tipo/errore- il controllo è necessario sugli input).

Ti permettono di "Duck-Type" molto facilmente (prendi una lista di diverse istanze di Classe - attiva la stessa chiamata di funzione su ciascuna, aspettandosi che ognuna abbia lo stesso metodo e abbia lo stesso formato di dati).

Ancora meglio con JavaScript:

Il mio codice .Iscriviti potrebbe anche essere scritta una sola volta, e quindi legato a tutto ciò che voglio "ereditare" esso.

Interface.Subscribe = function (publisher, evt_type) { 
    var self_ref = this; 
    publisher.Register(evt_type, self_ref); 
}; 

Class_1.Subscribe = Interface.Subscribe.bind(Class_1); 
Class_2.Subscribe = Interface.Subscribe.bind(Class_2); 
Class_3.Subscribe = Some_Other_Interface.Subscribe.bind(Class_3); 

E posso farlo liberamente, perché so che tutto quello che voglio iscrivermi alla sta per avere lo stesso pubblico-interfaccia.