2010-06-09 12 views
8

Después de haber hecho recientemente algunos desarrollos para iPhone, he notado un patrón de diseño interesante que se usa mucho en el SDK de iPhone, con respecto a la mutabilidad de objetos.Patrones de diseño de mutabilidad en Objective C y C++

Parece que el enfoque típico es definir una clase inmutable NSFoo, y luego derivar de ella un descendiente mutable NSMutableFoo. Generalmente, la clase NSFoo define miembros de datos, getters y operaciones de solo lectura, y el NSMutableFoo derivado agrega operaciones setters y mutating.

Al estar más familiarizado con C++, no pude evitar observar que esto parece ser completamente contrario a lo que haría al escribir el mismo código en C++. Aunque sin duda podría tomar, me parece que un enfoque más conciso es crear una sola clase Foo, marcar getters y operaciones de solo lectura como funciones const, y también implementar las operaciones mutables y los setters en la misma clase . Entonces terminarías con una clase mutable, pero los tipos Foo const*, Foo const& etc. son todos el equivalente inmutable.

Supongo que mi pregunta es, ¿tiene sentido mi opinión sobre la situación? Entiendo por qué Objective-C hace las cosas de manera diferente, pero ¿hay alguna ventaja en el enfoque de dos clases en C++ que me he perdido? ¿O me estoy perdiendo el punto por completo?

No es una pregunta demasiado seria, más por mi propia curiosidad que por otra cosa.

Respuesta

4

Objective-C es demasiado dinámico. En C++, la calificación de const se impone en tiempo de compilación, y cualquier violación de const-qualification en tiempo de ejecución (como la modificación de un objeto const calificado a través de un puntero no const-calificado) es un comportamiento indefinido.

Es en parte el mismo que el motivo por el que no hay métodos privados en Objective-C. Usted es libre de enviar cualquier mensaje que desee a cualquier objeto. El despacho en tiempo de ejecución toma un objeto y un mensaje, y resuelve una implementación de método para invocar.

si const objetos calificados sólo podían invocar const métodos calificados, arruinaría por completo la naturaleza dinámica de Objective-C y la Fundación porque tendría que ser hecho en tiempo de ejecución de un control de este tipo (primer cheque determinaría resuelve si el mensaje que se envía a una implementación certificada por const para esa instancia específica, y otra verificación para determinar si la instancia en sí misma fue const-qualified). Considere este ejemplo teórico:

NSArray *mutableArray = [[NSArray alloc] init]; 

NSString *mutableString = @"I am a mutable string"; 
const NSString *immutableString = @"I am immutable because I am const-qual'd"; 

[mutableArray addObject:mutableString]; 
[mutableArray addObject:immutableString]; // what happens?! 

// and what happens here (both immutable and mutable strings would respond 
// to the same selectors because they are the same class): 
[mutableArray makeObjectsPerformSelector:@selector(aMutableOperation)]; 

De repente pierde la dinámica. Como es ahora, los objetos mutables e inmutables pueden sentarse juntos en una colección inmutable o mutable.

Tener una subclase mutable mantiene la naturaleza dinámica de Objective-C y mantiene el tiempo de ejecución simple. Hubo un tema similar hace un tiempo acerca de los métodos privados.

0

Pensamientos ...

Mac, como usted sabe, en C++, se puede pensar en "A" y "const A" como dos tipos diferentes, siendo sus únicas relaciones

  1. " a" y "Un &" se puede lanzar de forma implícita a "const a" y "Const Un &", etc ...
  2. "const Un &" puede const_cast a "a &", etc ...

El compilador se encarga de la herencia y la propagación del tipo de modificador a través de expresiones, etc.

yo supongo que la gente NS eligieron el ..Mutable .. convención por un par de razones. Mi primera suposición es que creo que cuando NextStep fue originalmente creado, C no tenía soporte para "const" y todavía no tiene Object-Orientation. Y más importante aún, querían ciertas optimizaciones en sus implementaciones de objetos mutables frente a inmutables. Por ejemplo, en una clase de cadena inmutable como NSString, puede ser útil "agrupar" cadenas. Esto permite que las cadenas duplicadas se atomicen y que el proceso potencialmente use menos memoria. (Tiene ciertas desventajas, pero siempre hay compensaciones.)

En C++ puede dirigirse en la misma dirección entendiendo primero copy-on-write. Se dice que std :: string hace esto.

tema interesante,
Bradley

+1

'std :: string' puede usar COW para ahorrar en la copia, pero no está obligado a hacerlo en el estándar. Dado que COW es en realidad un éxito de rendimiento en un entorno multiproceso, pocas implementaciones todavía lo hacen. –

Cuestiones relacionadas