Abbiamo discusso la programmazione orientata agli oggetti per gli sviluppatori di giochi in generale e i principi specifici OOP di coesione e accoppiamento. Ora diamo un'occhiata a incapsulamento e come aiuta a mantenere il codice liberamente accoppiato e più mantenibile.
Nota: Sebbene questo suggerimento rapido sia spiegato usando Java, dovresti essere in grado di utilizzare le stesse tecniche e concetti in quasi tutti gli ambienti di sviluppo di giochi.
L'incapsulamento è il principio dell'occultamento delle informazioni. Questo è il implementazione (il funzionamento interno) di un oggetto è nascosto dal resto del programma.
Un esempio popolare che ascolterai per incapsulare è guidare una macchina. Hai bisogno di sapere esattamente come funziona ogni aspetto di un'auto (motore, carburatore, alternatore e così via)? No, devi sapere come usare il volante, i freni, l'acceleratore e così via.
Un altro esempio è la ricerca di un valore in una matrice. In Java, puoi fare quanto segue:
int myArray [] = 1, 2, 3, 5, 7, 9, 11, 13; Arrays.asList (myArray) .contains (11);
Il codice sopra restituirà vero
se il valore 11
è in myArray
, altrimenti tornerà falso
. Come fa il contains ()
metodo di lavoro? Quale tecnica di ricerca usa? Preordina l'array prima della ricerca? La risposta è non importa perché l'esatta implementazione del metodo è nascosta.
L'incapsulamento aiuta a creare codice che è liberamente accoppiato. Poiché i dettagli sono nascosti, riduce la capacità di altri oggetti di modificare direttamente lo stato e il comportamento di un oggetto.
Aiuta molto anche quando devi cambiare il tipo di dati di una variabile. Diciamo che hai deciso di usare un Stringa
per tenere traccia del tempo nel formato "hh: mm: ss". Dopo un po ', arrivi a capire che a int
rappresentare secondi potrebbe essere un tipo di dati migliore per il tempo. Non solo devi modificare il tipo di dati nell'oggetto, ma anche ogni volta che fai riferimento all'ora dell'oggetto nell'intero programma!
Invece, è possibile utilizzare le cosiddette funzioni getter e setter. Generatori e setter sono in genere piccole funzioni che restituiscono e impostano rispettivamente una variabile. Una funzione getter per ottenere il tempo dovrebbe apparire come segue:
public String getTime () tempo di ritorno;
Il getter restituirà a Stringa
valore: la variabile tempo
. Ora quando vogliamo cambiare tempo
ad un int, invece di cambiare tutte le chiamate al getter possiamo semplicemente cambiare la funzione getter per cambiare il int
tipo di dati in a Stringa
tipo di dati.
public String getTime () // divide il tempo in ore, minuti e secondi int ore = tempo / 3600; int resto = tempo% 3600; int minutes = resto / 60; int secondi = resto% 60; // // combina il risultato in una stringa restituita da due punti + ":" + minuti + ":" + secondi;Il
%
l'operatore è noto come operatore modulo e restituisce il resto di una divisione. Così 10% 3
sarebbe tornato 1
da 10/3 = 3
con un resto di 1
. La funzione getter ora restituisce a Stringa
e nessuna delle chiamate alla funzione deve cambiare. Il codice è quindi più gestibile.
Torniamo all'esempio di una nave che spara un proiettile introdotto nell'articolo di accoppiamento. Ricordiamo che abbiamo definito una nave come segue:
/ ** * La classe nave * / classe nave pubblica / ** * funzione - esegue il comportamento (attività) di trasformare la nave * / public void rotate () // codice che trasforma la nave / ** * Funzione - esegue il comportamento (compito) dello spostamento della nave * / movimento pubblico vuoto () // Codice che sposta la nave / ** * Funzione - esegue il comportamento (compito) di sparare con la pistola della nave * / incendio pubblico vuoto ( ) // Codice che fa sparare alla nave un proiettile
Per far sì che la nave spari un proiettile, tutto ciò che devi fare è chiamare ship.fire ()
. Il modo in cui il codice implementa sparare un proiettile non è importante, perché tutto quello che ci interessa è sparare un proiettile. In questo modo, se vuoi cambiare il codice per far scoppiare un laser, devi solo cambiare il metodo fuoco()
e non ogni chiamata a ship.fire ()
.
Questo ti permette di avere la possibilità di cambiare qualsiasi aspetto di come funziona la nave senza dover cambiare il modo in cui l'oggetto nave viene usato ovunque.
Tetris ha diversi modi per gestire le linee di compensazione. Incapsulare il comportamento di cancellare una linea ti permetterà di cambiare rapidamente il metodo che usi senza doverne riscrivere ogni uso. Questo ti permetterà anche di cambiare il metodo della linea chiara per creare diverse modalità di gioco nel gioco.
C'è un'altra caratteristica dell'incapsulamento che si occupa di nascondere l'accesso a un oggetto. Ci sono molte volte in cui non si desidera l'accesso esterno allo stato o al comportamento di un oggetto e quindi si desidera nasconderlo da qualsiasi altro oggetto. Per fare ciò, è possibile utilizzare modificatori del livello di accesso che forniscono o nascondono l'accesso agli stati e ai comportamenti degli oggetti.
I modificatori del livello di accesso definiscono due livelli di accesso:
pubblico
- qualsiasi oggetto può accedere in qualsiasi momento alla variabile o alla funzione.privato
- solo l'oggetto che contiene la variabile o la funzione può accedervi.(C'è un terzo livello - protetta
- ma lo copriremo in un post futuro.)
Ricorda che un fantasma aveva dichiarato di:
colore
nome
stato
direzione
velocità
... ed è stato definito come segue:
/ ** * The Ghost Class * / public class Ghost / ** * Function - move the Ghost * / public void move () // Codice che muove il Ghost nella direzione corrente / ** * Function - cambia Ghost direction * / public void changeDirection () // Codice che cambia la direzione del Ghost / ** * Function - change Ghost speed * / public void changeSpeed () // Codice che cambia la velocità del Ghost / ** * Function - cambia colore Ghost * / public void changeColor () // Codice che cambia il colore del Ghost / ** * Function - cambia Ghost * / public void changeState () // Codice che cambia lo stato del Ghost // Questa funzione anche chiamerà le tre funzioni di changeDirection (), changeSpeed () e changeColor ()
Da cambia colore()
, changeSpeed ()
, e Cambia direzione()
sono funzioni di supporto e non è previsto l'accesso da nessun'altra parte ma all'interno della classe, possiamo definirle come privato
funzioni. Possono anche essere dichiarati tutti gli stati del fantasma privato
dal momento che non dovrebbero essere modificati anche al di fuori della classe, e accessibili solo tramite le funzioni getter e setter. Ciò cambierebbe la classe da definire come segue:
/ ** * Ghost Class * / public class Ghost // Ghost afferma private String color; nome String privato; private Boolean isEatable; direzione del vettore privata; velocità int privata; / ** * Funzione - sposta il Ghost * / public void move () // Codice che muove il ghost nella direzione corrente / ** * Function - cambia Ghost direction * / private void changeDirection () // Code that cambia la direzione del Ghost / ** * Funzione - cambia la velocità Ghost * / private void changeSpeed () // Codice che cambia la velocità del Ghost / ** * Funzione - cambia il colore Ghost * / private void changeColor () // Codice che cambia il colore di Ghost / ** * Funzione - cambia stato Ghost * / public void changeState () // Codice che modifica lo stato di Ghost // Questa funzione chiama anche le tre funzioni di changeDirection, changeSpeed e changeColor / ** * Getter e setter * / ...
L'incapsulamento può aiutare a creare un codice più gestibile aiutando a prevenire l'effetto a catena delle modifiche al codice. Aiuta anche a creare codice liberamente accoppiato riducendo l'accesso diretto allo stato e al comportamento di un oggetto.
Nel prossimo suggerimento, discuteremo il principio dell'astrazione e come può aiutare a ridurre la ridondanza del codice. Seguici su Twitter, Facebook o Google+ per tenerti aggiornato con gli ultimi post.