Diciamo che ho qualche classe, e all'interno di istanze di quella classe voglio essere in grado di produrre determinati dati in vari tipi di file, ad es. CSV, SQL, PDF, ecc.
Il modo più semplice è solo una serie di istruzioni if, ma generalmente è un sistema chiuso. Chiunque desideri estendere il codice deve avere il controllo della classe e la possibilità di modificare il codice esistente.
Ecco un esempio davvero ingegnoso solo per dare qualcosa di più concreto:
class Animal:
def __init__(self,species,eats):
self.species = species
self.eats = eats
self.data_outputs {'sql':(server,table), 'csv':path}
def is_carnivorous(self):
self.eats == 'meat'
def is_hippie(self):
self.eats == 'wheatgrass'
def write(self,output_type,data):
output_loc = self.data_outputs[output_type]
if output_type == 'sql':
cursor = connection.cursor()
cursor.execute(some_insert_statement,data)
elif output_type == 'csv':
with open(path,"r") as out:
out.write(data)
Se la logica di write
è molto coinvolta, forse la delega a una classe per gestire la logica potrebbe rendere il metodo un po 'più pulito:
class Animal:
def __init__(self,species,eats):
self.species = species
self.eats = eats
self.data_outputs {'sql':(server,table), 'csv':path}
def is_carnivorous(self):
self.eats == 'meat'
def is_hippie(self):
self.eats == 'wheatgrass'
def write(self,output_type,data):
output_loc = self.data_outputs[output_type]
if output_type == 'sql':
SQLWriter.write(*output_loc,self.data)
elif output_type == 'csv':
CSVWriter.write(output_loc,data)
class SQLWriter:
def write(self,server,table,data):
cursor = connection.cursor()
cursor.execute(some_insert_statement,data)
class CSVWriter:
def write(self,path,data):
with open(path,"r") as out:
out.write(data)
In entrambi i casi, entrambi i sistemi sono chiusi, poiché la modifica del comportamento di scrittura richiede una sottoclasse dell'intera classe Animal
solo per sovrascrivere write
. Probabilmente è ancora peggio nell'esempio di delega della classe perché ora hai accoppiato la creazione della classe con il metodo write
così ora ogni volta che vuoi creare un nuovo tipo di output devi modificare il metodo write_data
, e crea la classe appropriata.
La soluzione pitonica è simile a questa per usare solo SQLWriter
e CSVWriter
come mixins?:
class Animal(CSVWriter):
def __init__(self,species,eats):
self.species = species
self.eats = eats
def is_carnivorous(self):
self.eats == 'meat'
def is_hippie(self):
self.eats == 'wheatgrass'
Ciò mantiene il sistema aperto, nel senso che chiunque desideri creare un nuovo tipo di output ha semplicemente bisogno di scrivere un nuovo mixin ed ereditare da esso, e nessun codice esistente deve essere toccato per farlo. Tuttavia, gli utenti di Animal
è necessario essere consapevoli che devono ereditare da un mixin per ottenere la capacità write
, che non sembra ideale.
Se il metodo di scrittura dipendeva dal tipo effettivo di classe contenente i dati ( Animal
in questo esempio), sarebbe semplice che avessi solo un metodo write
in quella classe che qualsiasi sottoclasse può oltrepassare. Ma in questo esempio voglio che il metodo write
sia polimorfico su dati specifici all'interno della classe, non sulla classe stessa.
Qual è la soluzione standard Pythonic (o più generalmente Object Oriented) per questo?
MODIFICA : se stai andando a downvotare, almeno spiegaci qual è il tuo problema con la domanda, così posso correggerlo di conseguenza.