Domanda Risolto Esercizio python stato oggetto che cambia

Stato
Discussione chiusa ad ulteriori risposte.

jr_sottomajor

Utente Silver
2 Luglio 2017
96
33
4
79
Ciao, stavo risolvendo questo esercizio:
  • Immaginiamo che un pacco venga inviato all’ufficio postale: il pacco puo` essere ordinato, poi spedito all’ufficio postale e quindi ricevuto dal destinatario.
  • Vogliamo scrivere il suo stato ogni volta che questo cambia: lo stato iniziale e` ordinato. La classe Pacco ha il metodo _succ per passare allo stato successivo e _pred per passare a quello precedente. Lo stato ordinato non ha stati che lo precedono; lo stato ricevuto non ha stati che vengono dopo di esso.
  • L’approccio piu` semplice sarebbe di aggiungere dei flag booleani e applicare dei semplici statement if/else all’interno di ciascun metodo. Cio` complicherebbe il nostro codice quando abbiamo piu` stati da considerare negli if/else.
  • Inoltre, la logica per tutti gli stati sarebbe dissemintata tra tutti i metodi . Usiamo qundi l’approccio state-specific.

Incluso nella traccia c'è questo codice:
Python:
def main():
    print("\nCreo il pacco")
    pacco=Pacco()
    pacco.stampaStato()
    print("\nInoltro il pacco all'ufficio postale")
    pacco.next()
    pacco.stampaStato()
    print("\nConsegno il pacco al destinatario")
    pacco.next()
    pacco.stampaStato()
    print("\nProvo a passare ad uno stato successivo")
    pacco.next()
    pacco.stampaStato()

if __name__== "__main__":
    main()


"""Il  programma deve stampare:
Creo il pacco
Il pacco e` stato ordinato ma non ancora spedito

Inoltro il pacco all'ufficio postale
Il pacco e` stato spedito ma non ancora ricevuto

Consegno il pacco al destinatario
Il pacco e` stato ricevuto

Provo a passare ad uno stato successivo
Il pacco e` gia` stato ricevuto
Il pacco e` stato ricevuto
"""


La mia soluzione è la seguente:

Codice:
class Pacco:
    def __init__(self):
        self.impl = Ordinato()
    def next(self):
        if isinstance(self.impl, Ordinato):
            self._succ(Spedito())
        elif isinstance(self.impl, Spedito):
            self._succ(Ricevuto())
        elif isinstance(self.impl, Ricevuto):
            print("Il pacco è già stato ricevuto")
    def _succ(self, newImpl):
        self.impl = newImpl
    def _pred(self, newImpl):
        self.impl = newImpl
    def stampaStato(self):
        self.impl.f()
    def __getattr__(self, nome):
        return getattr(self.impl, nome)

class Ordinato:
    def f(self):
        print("Il pacco e` stato ordinato ma non ancora spedito")

class Spedito:
    def f(self):
        print("Il pacco e` stato spedito ma non ancora ricevuto")

class Ricevuto:
    def f(self):
        print("Il pacco e` stato ricevuto")


#-------------
def main():
    print("\nCreo il pacco")
    pacco=Pacco()
    pacco.stampaStato()
    print("\nInoltro il pacco all'ufficio postale")
    pacco.next()
    pacco.stampaStato()
    print("\nConsegno il pacco al destinatario")
    pacco.next()
    pacco.stampaStato()
    print("\nProvo a passare ad uno stato successivo")
    pacco.next()
    pacco.stampaStato()

if __name__== "__main__":
    main()


"""Il  programma deve stampare:
Creo il pacco
Il pacco e` stato ordinato ma non ancora spedito

Inoltro il pacco all'ufficio postale
Il pacco e` stato spedito ma non ancora ricevuto

Consegno il pacco al destinatario
Il pacco e` stato ricevuto

Provo a passare ad uno stato successivo
Il pacco e` gia` stato ricevuto
Il pacco e` stato ricevuto
"""


Unico dubbio (funziona perfettamente e da' gli stessi output): ho usato degli if per fare il controllo dello stato, non so se sono andato contro la traccia. Esiste qualche altro modo per evitare gli if/elif? Non mi è chiaro quel metodo _pred a cosa possa servire, infatti non l'ho implementato... grazie in anticipo
 
Esiste qualche altro modo per evitare gli if/elif? Non mi è chiaro quel metodo _pred a cosa possa servire, infatti non l'ho implementato
La spiegazione della traccia o del perché vuole un _pred non te la so dare, ma se vuoi farlo senza if/else puoi procedere in questo modo:
Python:
class Pacco:
    def __init__(self):
        self.state = Ordinato()
    def next(self):
        self.state = self.state.next()
    def stampaStato(self):
        print(self.state)

class Ordinato:
    def __str__(self):
        return "Il pacco è stato ordinato ma non ancora spedito"
    def next(self):
        return Spedito()

class Spedito:
    def __str__(self):
        return "Il pacco è stato spedito ma non ancora ricevuto"
    def next(self):
        return Ricevuto()

class Ricevuto:
    def __str__(self):
        return "Il pacco è stato ricevuto"
    def next(self):
        return self

Evito di rispettare i canoni della consegna (_succ, _prec, "già", etc.) perché non ho intenzione di sbattermi per comprendere un testo poco esplicativo. Mi sono limitato a mostrarti l'approccio che l'esercizio vuole farti comprendere: inserire la logica di transizione all'interno degli stati. Se vuoi tener traccia del predecessore, puoi modificare il metodo next (degli stati, non di Pacco) per accettare come ulteriore parametro lo stato attuale, in questo modo se hai due o più percorsi che ti portano in un determinato stato (e.g., spedito perché regalato invece di spedito perché ordinato) puoi tenere traccia del vero predecessore.
 
  • Mi piace
Reazioni: jr_sottomajor
La spiegazione della traccia o del perché vuole un _pred non te la so dare, ma se vuoi farlo senza if/else puoi procedere in questo modo:
Python:
class Pacco:
    def __init__(self):
        self.state = Ordinato()
    def next(self):
        self.state = self.state.next()
    def stampaStato(self):
        print(self.state)

class Ordinato:
    def __str__(self):
        return "Il pacco è stato ordinato ma non ancora spedito"
    def next(self):
        return Spedito()

class Spedito:
    def __str__(self):
        return "Il pacco è stato spedito ma non ancora ricevuto"
    def next(self):
        return Ricevuto()

class Ricevuto:
    def __str__(self):
        return "Il pacco è stato ricevuto"
    def next(self):
        return self

Evito di rispettare i canoni della consegna (_succ, _prec, "già", etc.) perché non ho intenzione di sbattermi per comprendere un testo poco esplicativo. Mi sono limitato a mostrarti l'approccio che l'esercizio vuole farti comprendere: inserire la logica di transizione all'interno degli stati. Se vuoi tener traccia del predecessore, puoi modificare il metodo next (degli stati, non di Pacco) per accettare come ulteriore parametro lo stato attuale, in questo modo se hai due o più percorsi che ti portano in un determinato stato (e.g., spedito perché regalato invece di spedito perché ordinato) puoi tenere traccia del vero predecessore.
Grazie mille
 
Stato
Discussione chiusa ad ulteriori risposte.