objective-c cocoa-touch cocoa-design-patterns

objective c - Hacer que las clases Objective-C se vean hermosas



cocoa-touch cocoa-design-patterns (3)

Quería preguntarles sus opiniones sobre el código de olores en Objective C, específicamente Cocoa Touch. Estoy trabajando en un juego bastante complejo, y estoy a punto de comenzar la Gran Refactorización de diciembre.

Un buen número de mis clases, los modelos en particular, están llenos de métodos que se ocupan de la lógica empresarial interna; Los esconderé en una categoría privada, en mi guerra contra los archivos de encabezado masivos. Esas categorías privadas contienen una gran cantidad de declaraciones, y esto me hace sentir incómodo ... casi como Objective-C que me hace sentir culpable por todos estos métodos.

Cuanto más refactorice (¡algo bueno!), Más tengo que mantener toda esta duplicación (no tan buena). Simplemente se siente mal.

En un lenguaje como Ruby, la comunidad pone MUCHO énfasis en métodos muy cortos, claros y hermosos. Mi pregunta es, para Objective C (Cocoa Touch específicamente), ¿por cuánto tiempo se vuelven típicos sus métodos, cuán grandes son sus controladores y cuántos métodos por clase encuentran todos ustedes? ¿Hay ejemplos hermosos y bonitos de Clases formadas por métodos cortos en el Objetivo C, o simplemente no es una parte importante de la cultura del idioma?

DIVULGACIÓN: Actualmente estoy leyendo "The Little Schemer", que debería explicar mi tristeza, re: Objective C.


Lo primero que hago incluso antes de implementar clase o método es preguntar: "¿Cómo querría usar esto desde el exterior?"

Nunca, nunca empiezo escribiendo primero los aspectos internos de mis clases y métodos. Al comenzar con una API pública elegante, los internos tienden a ser elegantes de forma gratuita, y si no lo hacen, entonces la fealdad está contenida al menos en un único método o clase, y no se permite contaminar el resto del código con su olor. .

Hay muchos patrones de diseño, dos décadas de codificación me han enseñado que el único patrón que resiste la prueba del tiempo es: KISS . Keep It Simple Stupid.

Algunas reglas generales, para cualquier idioma o entorno:

  • ¡Sigue tu instinto sobre cualquier consejo que hayas leído o escuchado!
  • ¡Rescate temprano!
    • ¡Si es necesario, verifique las entradas temprano y rescate rápidamente! Menos limpieza para hacer.
  • Nunca agregue algo a su código que no use.
    • Una opción para "reversa" puede parecer algo agradable de tener en el futuro.
    • En ese caso agrégalo por el camino! No pierdas tiempo agregando complejidad que no necesitas.
  • Los nombres de los métodos deben describir lo que se hace, nunca cómo se hace.
    • Se debe permitir que los métodos cambien su implementación sin cambiar su nombre, siempre y cuando el resultado sea el mismo.
    • Si no puede entender qué hace un método con su nombre, ¡cambie el nombre!
    • Si la parte de cómo es lo suficientemente compleja, use comentarios para describir su implementación.
  • ¡No temas a los solteros!
    • Si su aplicación solo tiene un modelo de datos, ¡es un singleton!
    • Pasar una sola variable por todo el lugar es simplemente pretender que es algo más que un singleton y agregar complejidad como bonificación.
  • Planifique las fallas desde el comienzo.
    • Siempre use doFoo:error lugar de doFoo: desde el principio.
    • Crea buenas instancias NSError con descripciones localizadas legibles por el usuario final desde el principio.
    • Es un gran problema actualizar los mensajes / manejo de errores a una gran aplicación existente.
    • ¡Y siempre habrá errores si tienes usuarios y IO involucrados!
  • Cocoa / Objective-C está orientado a objetos *, no a una orientación de clase como la mayoría de los niños populares que dicen ser OOP.
    • No introduzca una clase de valores estúpida con solo propiedades, una clase sin métodos que realice el trabajo real podría ser una estructura.
    • ¡Deja que tus objetos sean inteligentes! ¿Por qué agregar una clase FooParser completamente nueva si un método fooFromString: en Foo es todo lo que necesita?
  • En Cocoa, lo que puedes hacer es siempre más importante que lo que eres .
    • No introduzca un protocolo si un objetivo / acción puede hacer.
    • No verifique que las instancias se ajusten a los protocolos, es un tipo de clase, que depende del compilador.

Mis 2 centavos:

  1. Las propiedades son generalmente mejores que getter + setter de estilo antiguo. Incluso si usa propiedades @dinámicas, declarelas con @property, esto es mucho más informativo y más breve.
  2. Personalmente no simulo métodos "privados" para las clases. Sí, puedo escribir una categoría en algún lugar del archivo .m (m), pero dado que Obj-C no tiene una forma pura de declarar un método privado, ¿por qué debería inventar uno? De todos modos, incluso si realmente necesita algo así, declare un "MyClassPrivate.h" por separado con una categoría e inclúyalo en los archivos .m (m) para evitar la duplicación de las declaraciones.
  3. Encuadernación Enlazando para la mayoría de las relaciones de la interfaz del controlador <->, use transformadores, formateadores, simplemente no escriba métodos para leer / escribir valores de controles manualmente. Hace que el código parezca algo de la era MFC.
  4. C ++ , muchos códigos parecen mucho mejores y más cortos cuando se escriben en C ++. Como el compilador entiende las clases de C ++, es un buen punto para refactorizar, especialmente cuando se trabaja con un código de bajo nivel.
  5. Por lo general, divido grandes controladores. Algo más de 500 líneas de código es un buen candidato para refactorizar para mí. Por ejemplo, tengo un controlador de ventana de documento, ya que algunas versiones de la aplicación se amplían con las opciones de importación / exportación de imágenes. El controlador crece hasta 1.000 líneas donde 1/2 es el "material de imagen". Eso es un "disparador" para mí para hacer un ImageStuffController, crear una instancia en el NIB y poner todo el código relativo a la imagen allí.

Todo lo anterior me facilita mantener mi código. Para proyectos grandes, donde dividir los controladores y las clases para mantener pequeños resultados, gran cantidad de archivos, generalmente intento extraer algún código en un marco. Por ejemplo, si una gran parte de la aplicación se está comunicando con servicios web externos, generalmente hay una forma directa de extraer un MyWebServices.framework de la aplicación principal.


La belleza es subjetiva Para mí, una clase de Objective-C es hermosa si es legible (sé lo que se supone que debe hacer) y mantenible (puedo ver qué partes son responsables de hacer qué). Tampoco me gusta que se me quite el código de lectura por un idioma desconocido. Más o menos como cuando estás leyendo un libro y lees algo que te saca de la inmersión y te recuerda que estás leyendo.

Probablemente recibas muchos consejos diferentes y mutuamente excluyentes, pero aquí están mis pensamientos.

  • No hay nada de malo en que los métodos privados estén en una categoría privada. Para eso está ahí. Si no te gustan las declaraciones que obstruyen el archivo, utiliza el código desplegable en el IDE o las extensiones como categoría en un archivo diferente.
  • Agrupe los métodos relacionados y #pragma mark con #pragma mark statements
  • Cualquiera que sea el diseño de código que use, la consistencia es importante. Tómese unos minutos y escriba sus propias pautas (aquí están las mine ), de modo que si olvida lo que se supone que debe hacer, tiene una referencia.
  • El controlador no tiene que ser el delegado y el origen de datos, siempre puede tener otras clases para estos.
  • Use nombres descriptivos para métodos y propiedades. Sí, puede documentarlos, pero no puede ver la documentación cuando Xcode aplica la finalización del código, donde los métodos y propiedades bien nombrados dan sus frutos. Además, los comentarios del código se vuelven obsoletos si no se actualizan mientras el código cambia.
  • No intentes escribir código inteligente. Puede pensar que es mejor encadenar una secuencia de llamadas de método en una línea, pero el compilador optimiza mejor de lo que podría pensar. Está bien usar variables temporales para mantener los valores (en su mayoría, estos son sólo indicadores de todos modos, por lo que son relativamente pequeños) si mejora la legibilidad. Escribir un código para que los humanos lo lean .
  • DRY se aplica a Objective-C tanto como a otros idiomas. No te preocupes por refactorizar el código en más métodos. No tiene nada de malo tener muchos métodos siempre que sean útiles.