It is also true that a system may become so coupled, where each class is dependent on other classes that depend on other classes, that it is no longer possible to make a change in one place without having a ripple effect and having to make subsequent changes in many places.[1] This is why using an interface or an abstract class can be valuable in any object-oriented software project.
Citazione da Wikipedia
A partire da zero
Sto iniziando da zero con un progetto che ho terminato di recente perché ho trovato il codice troppo stretto e difficile da refactoring, anche quando si utilizza MVC. Userò MVC anche sul mio nuovo progetto ma voglio provare ad evitare le insidie questa volta, si spera con il tuo aiuto.
Riepilogo del progetto
Il mio problema è che desidero davvero mantenere il controller il più pulito possibile, ma sembra che non possa farlo. L'idea di base del programma è che l'utente scelga elenchi di parole inviati al motore di gioco. Sceglierà le parole a caso dagli elenchi finché non ne rimarrà nessuno.
Problema a portata di mano
Il mio problema principale è che il gioco avrà 'modalità', e deve controllare l'input in modi diversi attraverso un metodo chiamato checkWord()
, ma esattamente dove metterlo e come estrarlo correttamente è una sfida per me . Sono nuovo per progettare modelli, quindi non sono sicuro che ce ne siano o potrebbero adattarsi al mio problema.
Il mio tentativo di astrazione
Ecco cosa ho ottenuto finora dopo ore di "refactoring" dei piani di progettazione, e so che è lungo, ma è il meglio che potrei fare per cercare di darti una panoramica (Nota: poiché questo è lo schizzo , qualsiasi cosa è soggetto a modifiche, tutti i consigli e l'aiuto sono ben accetti. Nota anche i punti di accoppiamento contrassegnati):
Lista di parole
class Wordlist {
// Basic CRUD etc. here!
// Other sample methods:
public function wordlistCount($user_id) {} // Returns count of how many wordlists a user has
public function getAll($user_id) {} // Returns all wordlists of a user
}
Parola
class Word {
// Basic CRUD etc. here!
// Other sample methods:
public function wordCount($wordlist_id) {} // Returns count of words in a wordlist
public function getAll($wordlist_id) {} // Returns all words from a wordlist
public function getWordInfo($word_id) {} // Returns information about a word
}
Wordpicker
class Wordpicker {
// The class needs to know which words and wordlists to exclude
protected $_used_words = array();
protected $_used_wordlists = array();
// Wordlists to pick words from
protected $_wordlists = array();
/* Public Methods */
public function setWordlists($wordlists = array()) {}
public function setUsedWords($used_words = array()) {}
public function setUsedWordlists($used_wordlists = array()) {}
public function getRandomWord() {} // COUPLING POINT! Will most likely need to communicate with both the Wordlist and Word classes
/* Protected Methods */
protected function _checkAvailableWordlists() {} // COUPLING POINT! Might need to check if wordlists are deleted etc.
protected function _checkAvailableWords() {} // COUPLING POINT! Method needs to get all words in a wordlist from the Word class
}
Gioco
class Game {
protected $_session_id; // The ID of a game session which gets stored in the database along with game details
protected $_game_info = array();
// Game instantiation
public function __construct($user_id) {
if (! $this->_session_id = $this->_gameExists($user_id)) {
// New game
} else {
// Resume game
}
}
// This is the method I tried to make flexible by using abstract classes etc.
// Does it even belong in this class at all?
public function checkWord($answer, $native_word, $translation) {} // This method checks the answer against the native word / translation word, depending on game mode
public function getGameInfo() {} // Returns information about a game session, or creates it if it does not exist
public function deleteSession($session_id) {} // Deletes a game session from the database
// Methods dealing with game session information
protected function _gameExists($user_id) {}
protected function _getProgress($session_id) {}
protected function _updateProgress($game_info = array()) {}
}
Il gioco
/* CONTROLLER */
/* "Guess the word" page */
// User input
$game_type = $_POST['game_type']; // Chosen with radio buttons etc.
$wordlists = $_POST['wordlists']; // Chosen with checkboxes etc.
// Starts a new game or resumes one from the database
$game = new Game($_SESSION['user_id']);
$game_info = $game->getGameInfo();
// Instantiates a new Wordpicker
$wordpicker = new Wordpicker();
$wordpicker->setWordlists((isset($game_info['wordlists'])) ? $game_info['wordlists'] : $wordlists);
$wordpicker->setUsedWordlists((isset($game_info['used_wordlists'])) ? $game_info['used_wordlists'] : NULL);
$wordpicker->setUsedWords((isset($game_info['used_words'])) ? $game_info['used_words'] : NULL);
// Fetches an available word
if (! $word_id = $wordpicker->getRandomWord()) {
// No more words left - game over!
$game->deleteSession($game_info['id']);
redirect();
} else {
// Presents word details to the user
$word = new Word();
$word_info = $word->getWordInfo($word_id);
}
Il bit da finire
/* CONTROLLER */
/* "Check the answer" page */
// ??????????????????
( link )
Assicurati di attivare 'Larghezza del layout' a destra per una vista migliore. Grazie in anticipo.
Domande
- In che misura gli oggetti dovrebbero essere accoppiati liberamente? Se l'oggetto A ha bisogno di informazioni dall'oggetto B, come si dovrebbe ottenere questo senza perdere troppa coesione?
- Come suggerito nei commenti, i modelli dovrebbero contenere tutta la logica aziendale. Tuttavia, poiché gli oggetti dovrebbero essere indipendenti, dove incollarli insieme? Il modello dovrebbe contenere una sorta di area "indice" o "cliente" che collega i punti?
Modifica:
Quindi, in pratica, quello che dovrei fare all'inizio è creare un nuovo modello che posso chiamare più facilmente con oneliner come $model->doAction(); // Lots of code in here which uses classes!
E il metodo per controllare le parole? Dovrebbe essere il proprio oggetto? Non sono sicuro di dove dovrei metterlo visto che è praticamente parte del 'gioco'. Ma d'altra parte, potrei semplicemente lasciare fuori l'astrazione e l'OOPness e renderlo un metodo del 'modello cliente' che sarà comunque incapsulato dal controller. Molto incerto su questo.