2010-03-24 14 views
14

OK Tengo 2 clases realmente grandes> 1k líneas cada una de las cuales actualmente se han dividido en varias. Luego se recombinan usando herencia múltiple. Ahora me pregunto, si hay alguna manera más limpia/mejor más pitonica de hacer esto. Completamente factorizarlos resultaría en cantidades interminables de llamadas self.otherself.do_something, que no creo que es la forma en que debería hacerse.Diseño de clase Python - División de clases grandes en múltiples para funcionalidad de grupo

Para aclarar las cosas aquí es lo que se ve actualmente como:

from gui_events import GUIEvents # event handlers 
from gui_helpers import GUIHelpers # helper methods that don't directly modify the GUI 

# GUI.py 
class GUI(gtk.Window, GUIEvents, GUIHelpers): 
    # general stuff here stuff here 

Un problema que es resultado de esta protestó Pylint darme billones de "no init llamado"/"atributo indefinido"/"atributo accede antes de la definición "advertencias".

EDIT:
Es posible que desee echar un vistazo al código, para hacerse una idea acerca de lo que todo el asunto es en realidad.
http://github.com/BonsaiDen/Atarashii/tree/next/atarashii/usr/share/pyshared/atarashii/

Tenga en cuenta, realmente estoy intentando cualquier cosa para mantener esta cosa lo más seco posible, estoy usando pylint para detectar la duplicación de código, lo único que se queja de las importaciones son.

+0

Algo no tiene sentido. La pregunta dice "> 1k líneas cada uno". El código real en el repositorio es de 356 líneas. Por favor, corrija la pregunta o el enlace. –

+0

Debe resumir: http://github.com/BonsaiDen/Atarashii/blob/next/atarashii/usr/share/pyshared/atarashii/gui.py http://github.com/BonsaiDen/Atarashii/blob/ next/atarashii/usr/share/pyshared/atarashii/gui_events.py y http://github.com/BonsaiDen/Atarashii/blob/next/atarashii/usr/share/pyshared/atarashii/gui_helpers.py ya que he dividido el cosas (actualmente el único tiene 968 líneas, porque recientemente cambié algunas cosas a otros archivos). También vea los archivos de vista *, que en conjunto tienen 1,1k líneas. –

Respuesta

6

Si desea usar la herencia múltiple para combinar todo en una clase grande (podría tener sentido hacerlo), puede refactorizar cada una de las clases principales para que cada método y propiedad sea privado (comienza con ' __ ') o tiene un prefijo corto de 2-3 caracteres exclusivo para esa clase. Por ejemplo, todos los métodos y propiedades en su clase GUIEvents podrían comenzar con ge_, todo en GUIHelpers podría comenzar con gh_. Al hacer esto, obtendrá algo de la claridad de utilizar instancias de subclase separadas (self.ge.doSomething() frente a self.ge_doSomething()) y evitará nombres de miembros conflictivos, que es el principal riesgo al combinar dichas clases grandes en una sola.

+0

Supongo que ese es el camino que seguiré aquí, porque 1. es fácil de hacer con una búsqueda/reemplazo, 2. reducirá la posibilidad de conflictos, también podré usar nombres más genéricos como um_get_items, en su lugar de (update_messages) .get_messages y 3. como ya lo ha dicho, traerá claridad al código y mostrará de dónde provienen los métodos. En general, es bastante simple, tal vez estoy pensando un poco complicarme después de pasar 5 semanas programando esto: D –

1

Creo que esto es más un problema general de diseño OO que un problema de Python. Python prácticamente te ofrece todas las herramientas OOP clásicas, convenientemente empaquetadas. Debería describir el problema con más detalle (por ejemplo, ¿qué contienen las clases GUIEvents y GUIHelpers?)

Un aspecto específico de Python a considerar es el siguiente: Python admite múltiples paradigmas de programación y, a menudo, la mejor solución es no OOP. Este puede sea el caso aquí. Pero, de nuevo, tendrá que agregar más detalles para obtener una respuesta significativa.

+0

Puedes echar un vistazo a las clases aquí: http://github.com/BonsaiDen/Atarashii/tree/next/atarashii/usr/share/pyshared/atarashii/ GUIEvents se trata principalmente de manejar cosas cuando el usuario hizo clic en un botón. GUIHelpers configura algunas cosas más pequeñas como etiquetas y otros, y también proporciona algunas funciones de utilidad como is_ready. Todavía no estoy completamente listo para decidir qué métodos pertenecen a cada una de las "subclases". –

0

Su código puede mejorarse sustancialmente implementando un diseño Modelo-Vista-Controlador. Dependiendo de cómo se configuran su GUI y su herramienta, también puede beneficiarse de porciones de "widgetización" de su GUI, de modo que en lugar de tener un modelo-vista-controlador gigante, usted tenga un modelo-vista-controlador principal que administre un montón de Controladores de vista de modelo más pequeños, cada uno para distintas partes de su GUI. Esto le permitiría dividir su herramienta y su GUI en muchas clases, y puede reutilizar porciones de la misma, reduciendo la cantidad total de código que necesita mantener.

Si bien python admite múltiples paradigmas de programación, para las herramientas de GUI, la mejor solución casi siempre será un diseño orientado a objetos.

+0

El problema es que actualmente no veo una manera de reducir todo el asunto aún más, Dialogs/TrayIcon y los HTMLViews ya están en sus propias clases, por lo que esta gran interfaz gráfica de usuario actualmente solo está administrando los enlaces entre ellos y configurando cosas como la barra de estado. Además, ya se secó el código hasta la muerte ... lo único que podía imaginar era dividir la GUI en un componente que realmente modifica las cosas visibles y el otro solo en el manejo de eventos y demás, pero eso daría como resultado la autogestión. llamadas foo:/ –

5

Comience por encontrar las clases que el modelo conceptos de mundo real que su aplicación necesita para trabajar. Esos son candidatos naturales para las clases.

Intente evite la herencia múltiple tanto como sea posible; raramente es útil y siempre algo confuso. En su lugar, use la composición funcional (relaciones "HAS-A") para otorgar atributos enriquecidos a sus objetos hechos de otros objetos.

Recuerde hacer que cada método haga una cosa pequeña, específica; esto necesariamente implica romper métodos que hacen demasiadas cosas en pedazos más pequeños.

Refactor casos donde se encuentran muchos de estos métodos se están duplicando la funcionalidad de los demás; esta es otra forma de encontrar colecciones naturales de funcionalidad que merecen estar en una clase distinta.

+1

+1: "2 clases realmente grandes> 1k líneas" Ouch. Eso claramente falla en el diseño de OO. Todos los controladores de eventos en una clase son claramente incorrectos. Event Helpers no es un diseño de clase. –

0

Una posibilidad es asignar funciones importadas a los atributos de la clase:

En a_part_1.py archivo:

def add(self, n): 
    self.n += n 
def __init__(self, n): 
    self.n = n 

Y en archivo de clase principal:

import a_part_1 

class A: 
    __init__ = a_part_1.__init__ 
    add = a_part_1.add 

O si no desea para actualizar el archivo principal cuando se agregan nuevos métodos:

class A: pass 

import a_part_1 
for k, v in a_part_1.__dict__.items(): 
    if callable(v): 
     setattr(A,k,v) 
Cuestiones relacionadas