Pergunta

Tendo feito recentemente algum desenvolvimento para iPhone, percebi um padrão de design interessante muito usado no SDK do iPhone, em relação à mutabilidade de objetos.

Parece que a abordagem típica existe para definir uma classe imutável NSFoo, e então derivar dele um descendente mutável NSMutableFoo.Geralmente, o NSFoo classe define membros de dados, getters e operações somente leitura, e os derivados NSMutableFoo adiciona setters e operações de mutação.

Estando mais familiarizado com C++, não pude deixar de notar que isso parece ser completamente o oposto do que eu faria ao escrever o mesmo código em C++.Embora você certamente poderia adotar essa abordagem, parece-me que uma abordagem mais concisa é criar um único Foo classe, marque getters e operações somente leitura como const funções e também implementar as operações mutáveis ​​​​e setters na mesma classe.Você acabaria com uma classe mutável, mas os tipos Foo const*, Foo const& etc, todos são efetivamente equivalentes imutáveis.

Acho que minha pergunta é: minha opinião sobre a situação faz sentido?Entendo por que o Objective-C faz as coisas de maneira diferente, mas há alguma vantagem na abordagem de duas classes em C++ que perdi?Ou estou perdendo completamente o foco?

Não é uma pergunta muito séria - mais para minha curiosidade do que qualquer outra coisa.

Foi útil?

Solução

Objective-C é muito dinâmico.Em C++, a qualificação const é aplicada em tempo de compilação, e quaisquer violações da qualificação const em tempo de execução (como modificar um objeto qualificado como const por meio de um ponteiro não qualificado como const) é um comportamento indefinido.

É parcialmente o mesmo motivo pelo qual não existem métodos privados no Objective-C.Você é livre para enviar qualquer mensagem que desejar para qualquer objeto.O despacho em tempo de execução pega um objeto e uma mensagem e resolve uma implementação de método a ser invocada.

se const objetos qualificados só poderiam invocar const métodos qualificados, isso arruinaria completamente a natureza dinâmica do Objective-C e do Foundation porque tal verificação precisaria ser feita em tempo de execução (a primeira verificação determinaria se a mensagem sendo enviada resolve para uma implementação qualificada const para aquela instância específica, e outra verificação para determinar se a própria instância foi qualificada como const).Considere este exemplo 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 você perde dinâmica.Da forma como está agora, objetos mutáveis ​​e imutáveis ​​podem ficar juntos em uma coleção imutável ou mutável.

Ter uma subclasse mutável mantém a natureza dinâmica do Objective-C e mantém o tempo de execução simples.Houve um tópico semelhante há algum tempo sobre métodos privados.

Outras dicas

Pensamentos...

Mac, como você sabe, em C++, você pode pensar em "A" e "const A" como dois tipos diferentes, com suas únicas relações sendo

  1. "A" e "A &" podem ser convertidos implicitamente em "const A" e "const A &", etc.
  2. "const A &" pode ser const_cast para "A &", etc...

O compilador lida com a herança e propagação do modificador de tipo por meio de expressões, etc.

Eu acho que o pessoal do NS escolheu o ..Mutable..convenção por alguns motivos.Meu primeiro palpite é que acredito que quando o NextStep foi originalmente lançado, C não tinha suporte para "const" e ainda não tem Orientação a Objetos.E o mais importante, eles queriam certas otimizações em suas estratégias mutáveis ​​vs.implementações de objetos imutáveis.Por exemplo, em uma classe de string imutável como NSString, pode ser útil "agrupar" strings.Isso permite que strings duplicadas sejam atomizadas e que o processo use potencialmente menos memória.(Tem certas desvantagens, mas sempre há compensações.)

Em C++ você poderia seguir na mesma direção entendendo primeiro copiar na gravação.Diz-se que std::string faz isso.

Tópico interessante,
Bradley

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top