Se un oggetto deve essere contrassegnato, dovrebbe essere creato con l'attributo flag?

0

Supponiamo di avere un oggetto di base con una manciata di punti di dati rilevanti per l'autore.

class A(object):
    def __init__(self, x, y, width, length):
        self.x = x
        self.y = x
        self.width = x
        self.length = x

Quindi continuiamo a istanziare diversi A oggetti e li inseriamo in un elenco, come i programmatori sono soliti fare.

Ora supponiamo che questi oggetti debbano essere controllati per uno stato particolare ogni tanto, ma non è necessario controllarli su ogni passaggio, perché il loro stato non cambia particolarmente rapidamente. Quindi un metodo di verifica è scritto da qualche parte:

def check_for_ticks(object_queue):
    for obj in object_queue:
        if obj.checked == 0 and has_ticks(obj):
            do_stuff(obj)
        obj.checked -= 1

Ah, ma aspetta: non è stato progettato con l'attributo obj.checked ! Beh, non è un grosso problema, Python è gentile e ti consente di aggiungere attributi ogni volta, quindi cambiamo il metodo un po '.

def check_for_ticks(object_queue):
    for obj in object_queue:
        try:
            obj.checked =- 1
        except AttributeError:
            obj.checked = 0
        if obj.checked == 0 and has_ticks(obj):
            do_stuff(obj)

Funziona, ma mi dà una pausa. I miei pensieri sono misti, perché mentre è un attributo funzionale per dare un oggetto e risolve un problema, l'attributo non è realmente usato dall'oggetto. A probabilmente non modificherà mai il proprio attributo self.checked , e in realtà non è un attributo di cui "ha bisogno di essere informato" - è semplicemente incredibilmente conveniente dargli quell'attributo di passaggio.

Ma - cosa succede se ci sono più metodi che potrebbero voler contrassegnare un oggetto? Sicuramente non si crea la classe con ogni attributo che potrebbe essere indicato da un altro metodo per

Dovrei dare agli oggetti nuovi attributi in questo modo? Se non dovessi, qual è l'alternativa migliore semplicemente dando loro nuovi attributi?

    
posta 27.02.2014 - 21:39
fonte

3 risposte

0

Ho visto esempi in cui funziona bene, ma è principalmente per POD che sono popolati dinamicamente da altro codice, dì come risultato di una query REST o database.

Di solito, quando vuoi raggiungere i dati di un altro oggetto, è un segno che le tue responsabilità sono nelle classi sbagliate, o che potresti usare un po 'di rearchitecting.

Il mio primo pensiero nel tuo caso particolare è creare una coda separata per gli oggetti non controllati e modificare qualsiasi codice abilita has_ticks a mettere anche l'oggetto nella coda degli oggetti deselezionati. Ciò avrebbe il vantaggio di non dover scorrere tutti i singoli elementi anche quando la maggior parte o tutti non hanno bisogno di controllo.

Un'altra opzione è il commento di tobias_k sulla creazione di un dict nella coda oggetto che associa l'oggetto a un valore controllato.

Un'altra opzione è nella rappresentazione interna della coda, memorizza un [A, checked] come ogni elemento dell'elenco invece di solo A .

Un altro approccio possibile è Decorator Pattern , con cui crei un wrapper che aggiunge la funzionalità desiderata. Quindi puoi avvolgerlo quando lo metti in coda e scartare quando lo rimuovi dalla coda. Il decoratore ha il vantaggio che puoi spostare molte delle funzionalità della tua funzione check_for_ticks nel tuo oggetto CheckedA , o altra funzionalità che appartiene realmente agli oggetti elemento anziché alla coda. La classe wrapper potrebbe essere simile a:

class CheckedA(A):
    def __init__(self, wrappedA):
        self.wrappedA = wrappedA
        self.checked = 0

    def check_for_ticks(self):
        if self.checked == 0 and has_ticks(self.wrappedA):
            do_stuff(self.wrappedA)
        self.checked -= 1

Un'altra opzione è solo chiamare do_stuff direttamente ogni volta che viene aggiunto un segno di spunta, se i requisiti lo consentono.

La creazione di un attributo al di fuori della classe aggiunge l'accoppiamento e, ancor peggio, che l'accoppiamento è invisibile a chiunque legga il codice sorgente della classe. Non hai alcuna protezione contro qualcun altro che fa la stessa cosa e usa lo stesso nome in modo incompatibile. Hai molte altre opzioni prima di dover ricorrere a questo tipo di soluzione.

    
risposta data 27.02.2014 - 23:08
fonte
0

Un metodo consiste nel creare una classe companion che abbia l'attributo checked in esso con l'oggetto primario usando il pattern Delegate. Tuttavia, ciò significa che i tuoi elenchi devono essere elenchi di oggetti complementari e non di oggetti primari.

In pratica, aggiungere un attributo flag o di stato non è necessariamente un grosso problema. Tuttavia, tende a non scalare bene.

Il metodo che stai usando è possibile in Python e in un paio di altre lingue interpretate. Mi fa sentire icky dentro, quindi capisco il tuo disagio.

    
risposta data 27.02.2014 - 21:47
fonte
0

Avere un membro "controllato" del tuo oggetto accoppia direttamente il tuo oggetto e algortihm. A volte questo è accettabile, perché tra loro esiste un naturale accoppiamento. Nel caso di un algoritmo di garbage collection, la maggior parte ha alcuni flag su ciascun oggetto perché esiste un insieme fisso di operazioni che si verificheranno sull'oggetto.

Se stai cercando un modo per fare la stessa cosa senza l'accoppiamento, considera l'utilizzo di un oggetto set. I set di Python sono veloci (usano gli hash), quindi in genere è sicuro farlo

checked = set()
...
if obj not in checked:
    checked += obj

In Python, questo è in realtà veloce quanto avere un attributo sull'oggetto. In un linguaggio strongmente tipizzato come C ++, è probabile che l'attributo sia più veloce, ma ho trovato alcuni casi nell'applicazione reale in cui la differenza di velocità è stata abbastanza importante.

    
risposta data 27.02.2014 - 23:06
fonte

Leggi altre domande sui tag