È possibile accedere a un metodo di classe in un'istanza e in modo statico?

3

Sono relativamente nuovo al design di classe e ho un compito che non sono sicuro del modo migliore per completare, o se la mia idea in generale è un odore di codice.

Sto sviluppando un gioco di ruolo in cui le persone possono possedere mostri, quindi ognuno è un'istanza di oggetto della classe Monster. Dato che lo sprite di un mostro cambia a seconda di diversi fattori, la classe Monster ha un metodo per disegnare lo sprite che chiamo che fa tutti i controlli e la logica e visualizza lo sprite corretto usando le proprietà dell'oggetto e io lo chiamo come:

$Monster->drawSprite();

Questo metodo esegue controlli usando altri metodi di classe, come

$this->isHoldingItem();

che controlla i dati dal database utilizzando un ID mostro univoco (una proprietà di classe) e memorizzato come proprietà dell'oggetto.

Ogni tanto per la storia e in altri luoghi, voglio disegnare uno sprite mostro che non è in realtà di proprietà di nessuno, quindi non ha istanze di righe o istanze di database. Piuttosto che codificare l'URL dell'immagine o duplicare il mio codice, esiste un modo in cui un metodo può essere chiamato sia come parte di un'istanza sia staticamente e risponde di conseguenza? Questa è anche una buona idea?

Quindi nella mia testa potrei fare:

 $Monster->drawSprite();    

Questo userà le proprietà dell'istanza per determinare tutta la logica necessaria per visualizzare lo sprite, oppure potrei fare:

Monster::drawSprite();

Disegnare un mostro sprite senza fare affidamento sulle proprietà della classe. Forse potrei passare un array come argomento per tutti i controlli necessari sulle proprietà degli oggetti su cui solitamente si basa il metodo.

Immagino di poter fare qualcosa usando func_get_args () o molti condizionali, ma ho visto che si trasformava rapidamente in spaghetti code. È una buona idea, o è addirittura possibile? Mi riferisco specificamente a PHP con questa domanda.

    
posta Roy 20.01.2015 - 16:45
fonte

2 risposte

3

Questa non è una risposta alla tua domanda, ma una soluzione al tuo problema.

Il problema qui è che $Monster->drawSprite() è un non-starter; avere mostri sanno come disegnare se stessi è una violazione del Principio di Responsabilità Unica. Per lo stesso motivo, non ha senso cercare di far sì che un metodo esegua il "doppio lavoro" sia come metodo di istanza sia come metodo statico, poiché non si desidera affatto il metodo di istanza.

Devi separare la logica di gioco dall'I / O. Più in particolare, dovresti essere in grado di eseguire il ciclo di gioco senza alcun dispositivo video / audio / input (e non intendo fornire interfacce fittizie no-op). Una buona soluzione sarebbe simile a questa:

  • La classe Monster contiene solo dati pertinenti alla logica di gioco.
  • Esiste una mappatura da tipi di mostri (e altri tipi di entità di gioco) agli sprite corrispondenti (e agli effetti sonori, ecc.) Ciò potrebbe comportare l'aggiunta di un nuovo campo agli oggetti del gioco.
  • Esiste una funzione per passare dalle coordinate del mondo di gioco alle coordinate dello schermo. (Questa è ancora una questione di separazione delle preoccupazioni. Separarle ha il vantaggio che la logica di gioco non sarà influenzata dalla risoluzione grafica.)
  • Esiste una funzione drawSprite che prende le coordinate dello sprite e dello schermo e la disegna semplicemente.

Durante il normale gameplay esegui iterazioni su tutte le entità di gioco, trova lo sprite corretto, calcola le sue coordinate dello schermo, scopri se è persino visibile e passa tutte le informazioni a drawSprite . Durante gli eventi scriptati chiami semplicemente drawSprite direttamente.

Potrebbe sembrare un lavoro extra, ma sarai grato di averlo fatto man mano che il tuo gioco cresce. Tenere separati IO e logica significa che puoi ragionare su di loro più facilmente, testarli separatamente, rende impossibile modificare il codice grafico per infrangere la tua logica di gioco e riduce l'ambito che devi osservare quando si insinua un bug.

    
risposta data 20.01.2015 - 18:03
fonte
2

Se un metodo usa $ questo non può essere chiamato staticamente. O almeno, non dovrebbe essere chiamato staticamente anche se un qualche strano comportamento di PHP lo consente. Non si sa mai con PHP.

Se insisti a mantenere la tua architettura così com'è, cioè con i mostri che disegnano se stessi (che non è una buona architettura, come ha detto Doval), il modo più semplice sarebbe qualcosa di simile.

La classe Monster ha un metodo statico drawSprite ($ img_url, $ forse_other_params) che accetta tutti i dati necessari per disegnare un mostro come argomenti. Puoi passarlo, cioè l'URL dell'immagine. Ha anche un metodo drawSelf () che disegna se stesso, come fa il drawSprite () corrente, ma chiamando drawSprite () e passando tutti i parametri richiesti.

$usersMonster->drawSelf(); //called non statically
Monster::drawSprite($img_url, $other_stuff); // called statically

class Monster
{
    public function drawSelf()
    {
        $other_stuff = someComplicatedLogic();
        self::drawSprite($this->img_url, $other_stuff);
    }
    public static function drawSprite($img_url, $other_stuff)
    {
         // do the sprite drawing stuff
    }
}

Anche se dovrei sottolineare ancora una volta non è una buona architettura. Il suggerimento di Doval è ciò di cui hai veramente bisogno. Anche se non è un'app complicata ... soprattutto se non è un'app complicata: inizia a sviluppare buone abitudini presto, prima di passare a cose complicate.

    
risposta data 23.01.2015 - 15:17
fonte

Leggi altre domande sui tag