Apostila Programação Orientada a Objetos Objective C Traduzida PT BR

 

Programação Orientada a Objetos com Objective-C

Programação Orientada a Objeto

Como seres humanos, somos constantemente confrontados com uma miríade de fatos e impressões que devem fazer sentido. Para isso, devemos abstrair as estruturas básicas para longe de detalhes da superfície e descobrir as relações fundamentais no trabalho. Abstrações revelam as causas e efeitos, expõem padrões e frameworks, e separam o que é importante do que não é. Orientação a objetos fornece uma abstração dos dados em que você opera, além disso, ele fornece um agrupamento concreto entre os dados e as operações que você pode realizar com os dados – em vigor dando o comportamento dos dados.

Dados e Operações

Linguagens de programação possuem tem tradicionalmente dividido o mundo em duas partes – dados e operação nos dados. Dados são estáticos e imutáveis, exceto quando uma operação pode mudá-los. Os procedimentos e funções que operam nos dados não têm estado duradouro próprio, eles são úteis apenas na sua capacidade de afetar os dados.

 Esta divisão é, naturalmente, baseada na forma como os computadores funcionam, por isso não é aquele que você pode facilmente ignorar ou deixar de lado. Como as distinções igualmente difundida entre matéria e energia e entre substântivos e verbos, forma o contexto no qual trabalhamos. Em algum momento, todos os programadores – mesmo orientado a objeto programadores devem expor as estruturas de dados que seus programas vão usar e definir as funções que irão atuar sobre os dados.

 Com uma linguagem de programação procedural, como C, isso é tudo que existe para ela. A linguagem pode oferecer vários tipos de apoio para a organização de dados e funções, mas não vai dividir o mundo de forma diferente. Funções e estruturas de dados são os elementos básicos de design.

 Todo objeto possui ambos, estado(dados) e comportamento(método) (dados e operações). Nisto, eles não são muito diferentes de objetos físicos ordinários. É fácil ver como um dispositivo mecânico, como um relógio de bolso ou um piano, encarnando tanto estado e comportamento. Mas quase tudo o que foi projetado para fazer um trabalho faz também. Coisas mesmo simples, sem partes móveis, como uma garrafa comum que combina estado (como garrafa cheia, se está ou não aberta, ou como seu conteudo está ou não aquecido) com o comportamento ( a habilidade de distribuir seu fluxo em varios niveis diferentes, como ser aberta ou fechada, para resistir a temperaturas altas ou baixas).

 É esta a semelhança com as coisas reais que dão aos objetos muito de seu poder e de recursos. Eles podem não somente modelar os componentes do sistema real, mas igualmente cumprir bem as funções atribuídas como componentes de sistema de softwares.

Interface e Implementação

Você precisa ser capaz de captar abstrações e expressá-las na elaboração do programa. É o trabalho de uma linguagem de programação ajudar você a fazer isso. A linguagem deve facilitar o processo de invenção e design, permitindo que você codifique abstrações que revelam a forma como as coisas funcionam. Ela deve deixá-lo fazer a sua ideias concretas no código que você escreve. Detalhes superficiáis não deve obscurecer a arquitetura do seu programa.

 Todas as linguagens de programação oferecem dispositivos que ajudam a expressar abstrações. Em essência, estes dispositivos são maneiras de agrupar os detalhes de implementação, escondendo-os, e dando-lhes, pelo menos em certa medida, uma interface comum, tanto quanto um objecto mecânico separa a sua interface com a sua aplicação, como na imagem abaixo:


Olhando para essa unidade de dentro, como o implementador, você estaria preocupado como ele é composto e como ele funciona. Olhando de fora, como o usuário, você está preocupado apenas com o que ele é eo que ele faz. Você pode olhar o passado os detalhes e pensar somente em termos do papel que desempenha a unidade em um nível superior.

As principais unidades de abstração na linguagem C são as structures e funções. Ambos, de maneiras diferentes, ocultam elementos da aplicação:

  • No lado do mundo dos dados, structures C agrupam dados e elementos em grandes unidades que podem entao serem manipuladas como endidades individuais. Enquanto alguns códigos devem se aprofundar dentro da structure e manipular os campos separadamentes,  grande parte do programa pode considerá-lo como uma única coisa, não como uma coleção de elementos,mas como o que esses elementos recebidos representam em conjunto.Uma structure pode incluir outras, então um arranjo complexo de informação pode ser construído a partir de camadas simples. No C moderno, os campos de uma structure vive em seu próprio namespace, ou seja, seus nomes não entrarão em conflito com elementos de dados com os mesmos nomes fora da estrutura. Particionar o namespace do programa é essencial para manter os detalhes de implementação de interface. Imagine, por exemplo, a enorme tarefa de atribuir um nome diferente para cada pedaço de dados em um programa grande e de certificar que novos nomes não irão entrar em conflito com os antigos.

  • No lado processual do mundo, funções de encapsular comportamentos que podem ser utilizadas repetidamente sem ser reimplementedo. Os elementos de dados locais para uma função, como os campos dentro de uma estrutura, estão protegidos dentro de seu próprio namespace. Porque as funções podem referênciar (chamar) outras funções, podendo assim formar comportamentos complexos, que podem ser construídos a partir de pedaços menores.

   Funções são reutilizáveis. Uma vez definida, elas podem ser chamadas qualquer número de vezes, sem novamente considerar a implementação. As funções mais geralmente úteis podem ser coletadas em bibliotecas e reutilizados em diferentes aplicações. Tudo que o usuário precisa é a interface da função, e não o código-fonte.

  No entanto, ao contrário de elementos de dados, as funções são não divididas em namespaces separados. Cada função deve ter um nome único. Embora a função pode ser reutilizável, o seu nome não é.

Estruturas e funções C são capazes de expressar abstrações significativas, mas mantem a distinção entre dados e operações nos dados. Em uma linguagem de programação procedural, as maiores unidades de abstração ainda vivem de um lado ou do outro da divisão versus operações de dados. Os programas que você desenha devem sempre refletir, ao mais alto nível, a forma como o computador funciona.

 Linguagens de programação orientadas a objeto não perde nenhuma das virtudes de estruturas e funções, eles vão um passo além e adicionam uma unidade capaz de abstrair em um nível mais elevado, uma unidade que esconde a interação entre uma função e seus dados.

Suponha, por exemplo, que você tenha um grupo de funções que atuam sobre uma estrutura de dados particular. Você quer tornar essas funções mais fácil de se usar, tanto quanto possível, tendo a estrutura separada da interface. Então você deve fornecer algumas funções adicionais para gerenciar os dados. Todo o trabalho de manipular a estrutura de dados – a alocação de memória para ele, sua inicialização, a obtenção de informações a partir dele, modificar os valores dentro dele, mante-lo atualizado, e liberar sua memória – é feito através das funções. Tudo que o usuário faz é chamar as funções e passar a estrutura para eles.

 Com essas mudanças, a estrutura torna-se um token opaco que outros programadores nunca precisam olhar para por dentro. Eles podem se concentrar no que as funções de fazem, e não sobre a forma como os dados são organizados. Você já deu o primeiro passo para a criação de um objeto.

O próximo passo é dar esse idéia de suporte na linguagem de programação e esconder completamente a estrutura de dados de modo que não tem sequer a ser transmitida entre as funções. Os dados torna-se um detalhe de implementação interna, tudo o que é exportado para os usuários é uma interface funcional. Como os objetos encapsulam completamente os seus dados (ocultam), os usuários podem pensar neles unicamente em termos de seu comportamento.

 Com este passo, a interface com as funções tornou-se muito mais simples. Chamadores não precisam saber como eles são implementados (quais os dados que eles usam). É correto agora chamar isso de um objeto.

 A estrutura de dados escondido une todas as funções que compartilham o acesso a ele. Assim, um objeto é mais do que uma coleção de funções aleatórias, é um conjunto de comportamentos relacionados que são apoiadas por dados compartilhados. Para usar uma função que pertence a um objeto, você cria o objeto (dando-lhe assim a sua estrutura de dados interna) e, em seguida, dizer ao objeto qual a função que deve executar. Você começa a pensar em termos do que faz o objeto, em vez de em termos de cada uma das funções.

Esta progressão de pensamento sobre as funções e estruturas de dados, até pensamentos sobre comportamentos e objeto é a essência da aprendizagem de programação orientada a objetos. Pode parecer estranho no começo, mas conforme você ganha experiência com programação orientada a objeto, você acha que é uma forma mais natural de pensar sobre as coisas.A aplicação destas coisas como objetos de programação simplesmente estende a analogia de uma forma natural.

 Uma linguagem de programação pode ser avaliada pelos tipos de abstrações que permite codificar. Você não deve se distrair com assuntos irrelevantes ou forçados a se expressar usando um vocabulário que não coincide com a realidade que você está tentando capturar.

 Se, por exemplo, você sempre tende a manter os dados do projeto, corretamente combinados com o procedimento correto, você é forçado em todos os momentos estar ciente de todo o programa em um baixo nível de execução. Enquanto você ainda pode inventar programas em um alto nível de abstração, o caminho da imaginação para a implementação pode se tornar muito tênue, e cada vez mais difícil, pois os programas se tornam maiores e mais complicadas.

 Ao fornecer um nivel mais alto de abstração, as linguagens de programação orientadas a objeto, oferecem um vocabulário maior e um modelagem mais rica para se programar.

Modelo de Objeto

   A visão de programação orientada a objeto é combinar o estado e o comportamento – dados e operações sobre dados – em uma unidade de algo nível, um objeto, e dar suporte a linguagem. Um objeto é um conjunto de funções relacionadas e uma estrutura de dados; dados estes que são usados por essas funções. As funções são conhecidos como métodos de objetos, e os campos destas estruturas de dados são as suas variáveis ​​de instância. Os métodos se envolvem em torno das variáveis de instância e as esconde do resto do programa, como na ilustração abaixo:

 Um Objeto:

 

Se você já abordou qualquer tipo de dificuldade em problemas de programação, é provável que o seu projeto incluiu grupos de funções que trabalham em um tipo particular de dados – “objetos” implícitos sem o suporte ao idioma. Programação orientada a objetos torna esses grupos de funções explícitas e permite que você pense em termos de grupo, ao invés de seus componentes. O único caminho para os dados de um objeto, é somente pela interface, ou seja através de seus métodos.

 Através da combinação de estado e comportamento em uma única unidade, um objeto torna-se mais do que sozinho; a totalidade é realmente maior que a soma de suas partes. Um objeto é uma espécie de “subprograma” auto-suficiente, com jurisdição sobre uma área funcional específica. Ele pode desempenhar um papel de pleno direito modular dentro de um projeto de programa maior.

Terminologia: a  terminologia orientada a objetos varia de língua para língua. Por exemplo, em   C + +, os métodos são chamados de funções membro e variáveis ​​de instância são conhecidos como membros de dados. Este documento usa a terminologia de Objective-C, que tem sua base em Smalltalk.

  Por exemplo, se você tivesse que escrever um programa que modele o consumo de água em casa, você pode inventar objetos para representar os vários componentes do sistema de distribuição de água. Um pode ser um objeto Torneira que tem métodos para iniciar e parar o fluxo de água, ajustar a taxa de fluxo, retornar a quantidade de água consumida em um determinado período, e assim por diante. Para fazer este trabalho, um objeto Torneira precisaria variáveis ​​de instância para controlar se a torneira está aberta ou fechada, quanta água está sendo usado, e de onde a água está vindo.

Claramente, um objeto Torneira programático pode ser mais esperto do que um real (é análoga a uma torneira mecânica com lotes de medidores e instrumentos agregados). Mas mesmo uma torneira de verdade, como qualquer componente do sistema, exibe estado e comportamento. Para modelar efetivamente um sistema, você precisa de unidades de programação, como objetos, que também combinam estado e comportamento.

Um programa consiste numa rede de objectos interconectados que chamam uns aos outros para resolver uma peça do puzzle (como ilustrado na Figura Abaixo). Cada objeto tem um papel específico a desempenhar na concepção geral do programa e é capaz de comunicar-se com outros objetos. Objetos se comunicam através de mensagens, que são solicitações para executar métodos.

 

Objetos em rede

.

 Os objectos na rede não serão todos iguais. Por exemplo, além de objetos Torneira, o programa que modela o uso da água também pode ter objetos de tubos que podem fornecer água para os objetos torneira, e válvula para regular o fluxo entre os tubos. Poderia ser um objeto de Imóvel para coordenar um conjunto de tubos, válvulas e torneiras, alguns objetos Electrodoméstico — correspondente a máquinas de lavar louça, banheiros e máquinas de lavar — que podem mudar as válvulas para on e off, e talvez alguns objetos do usuário que operem os aparelhos e torneiras. Quando um objeto Imóvel é perguntado quanta água está sendo usado, ele pode invocar cada objeto Torneira e válvula para informar seu estado atual. Quando um usuário ligar um aparelho, o aparelho terá de ligar uma válvula para obter a água de que necessita.


A Metáfora de Mensagens

 Cada paradigma de programação vem com sua própria terminologia e metáforas. O jargão associado com programação orientada a objeto convida você a pensar sobre o que se passa em um programa a partir de uma perspectiva particular.

 Há uma tendência, por exemplo, de pensar em objetos como atores e dotá-los de humanos como as intenções e capacidades. É tentador às vezes para falar sobre um objeto decidindo o que fazer com uma situação, pedindo outros objetos para obter informações, introspecção sobre si mesmo para obter as informações solicitadas, delegando a responsabilidade para outro objeto, ou gestão de um processo.

 Ao invés de pensarmos em termos de funções ou métodos que fazem o seu trabalho, como seria em uma linguagem de programação procedural, esta metáfora lhe pede para pensar em objetos que realizam seus métodos. Os objetos não são recipientes passivos para o estado e comportamento, mas são considerados os agentes ativos do programa.

 Essa metáfora é realmente muito útil. Um objeto é como um ator em alguns aspectos: Ele tem um papel especial a desempenhar dentro do projeto global do programa, e dentro desse papel que pode agir de forma justa independentemente das outras partes do programa. Ele interage com outros objetos como ele, que desempenham seus próprios papéis, mas é auto-suficiente e, até certo ponto pode agir por conta própria. Como um ator no palco, ele não pode desviar-se do script, mas o papel que desempenha pode ser multifacetada e complexa.

 A idéia de objetos como atores se encaixa muito bem com a principal metáfora de programação orientada a objetos, a idéia de que os objetos se comunicam através de mensagens. Em vez de chamar um método como se fosse uma função, você envia uma mensagem a um objeto pedindo-lhe para executar um de seus métodos.

 Embora possa levar algum tempo para se acostumar, esta metáfora conduz a uma forma útil de olhar para métodos e objetos. Ele abstrai os métodos , longe dos dados particulares que atuam sobre o comportamento e se concentra em seu lugar. Por exemplo, em uma interface de programação orientada a objeto, um método start pode iniciar uma operação, um método de arquivo pode arquivar informações e um método draw pode produzir uma imagem. Exatamente quais operações são iniciadas, quais informações são arquivadas, e quais imagens são desenhadas não é revelado pelo nome do método. Diferentes objectos podem realizar estes métodos de diferentes maneiras.

Assim, os métodos são um vocabulário de comportamentos abstratos. Para chamar um desses comportamentos, você tem que fazê-lo concretoao associar o método com um objeto. Isto é feito por nomear o objecto como o receptor de uma mensagem. O objeto que você escolher como receptor determina o funcionamento exato em que é iniciada, os dados que são arquivados, ou a imagem que está desenhado.

 Assim, os métodos são um vocabulário de comportamentos abstratos. Para chamar um desses comportamentos, você tem que torna-lo concreto pela associação do método com um objeto. Isto é feito por nomear o objecto como o receptor de uma mensagem. O objeto que você escolher como receptor determina o funcionamento exato em que é iniciado, os dados que são arquivados, ou a imagem que é desenhada.

 Como os métodos pertencem aos objectos, que apenas podem ser invocado por um receptor em particular (o dono do método e da estrutura de dados do método irá actuar sobre). Diferentes receptores podem ter diferentes implementações do mesmo método. Conseqüentemente, diferentes receptores podem fazer coisas diferentes em resposta à mesma mensagem. O resultado de uma mensagem não pode ser calculado a partir da mensagem ou método nome sozinho, mas também depende do objecto que recebe a mensagem.

 Separando a mensagem (o comportamento requerido) do receptor (o proprietário de um método que pode responder ao pedido), a metáfora de mensagens capta perfeitamente a ideia de de que os comportamentos podem ser abstraír suas implementações específicas.


Classes

 Um programa pode ter mais de um objeto do mesmo tipo. Um programa pode ter mais do que um objecto do mesmo tipo. O programa que modela o consumo de água, por exemplo, pode ter várias torneiras e canos e talvez um punhado de aparelhos e usuários. Objectos do mesmo tipo são considerados membros da mesma classe. Todos os membros de uma classe são capazes de realizar os mesmos métodos e têm correspondêntes conjuntos de variáveis ​​de instância. Eles também compartilham uma definição comum, cada tipo de objeto é definido apenas uma vez.

 Neste, os objetos são semelhantes a estruturas C. Declarando uma estrutura que define um tipo. Por exemplo:

 struct key {

    char *word;
    int count;
};

 A declaração acima define o tipo struct key. Depois de definí-la, o nome da structure pode ser usado para produzir qualquer número de instancias do mesmo tipo:

 struct key a, b, c, d;

 struct key *p = malloc(sizeof(struct key) *MAXITEMS);

A declaração é um modelo para um tipo de estrutura, mas isso não cria uma structure que o programa possa usar. Isso leva a um outro passo para alocar memória para uma structure real desse tipo, um passo que pode ser repetido qualquer numero de vezes.

 Da mesma forma, definir um objeto cria um modelo para um tipo de objeto. Ele define uma classe de objetos. O modelo pode ser usado para produzir qualquer número de semelhantes objetos — as instâncias da classe. Por exemplo, haveria uma única definição da classe torneira. Usando esta definição, um programa pode alocar o maior número de instâncias de torneira quantas vezes for necessário.

 Uma definição de classe é como uma definição de structure pelo fato de que estabelece um conjunto de elementos de dados (variáveis ​​de instância), que se tornam parte de cada instância. Cada instância possui uma memória alocada para o seu próprio conjunto de variáveis ​​de instância, que armazenam valores específicos para a instância.

 No entanto, uma definição de classe é diferente de uma declaração de estrutura pelo fato de que também define métodos que especificam o comportamento dos membros da classe. Cada exemplo é caracterizada pelo seu acesso aos métodos definidos para a classe. Dois objetos com estruturas de dados equivalentes, mas diferentes métodos não pertencem à mesma classe.

Modularidade

 Para um programador C, um modulo é nada mais que um arquivo contendo o código fonte. Dividindo um grande programa (ou mesmo não tão grande) em arquivos diferente é um modo conveniente de dividí-lo em peças gerenciáveis. Cada peça pode ser trabalhada independentemente e compilada sozinha, e então integrada com outras peças quando o programa é conectado.

 Usando a classe designadora de armazenamento static para limitar o limite de nomes para somente os arquivos os quais foram declarados, melhorando a independência dos módulos fontes. Este tipo de módulo é uma unidade definida pelo sistema de arquivos. É um recipiente para o código-fonte, e não uma unidade lógica da língua. O que vai para dentro do recipiente depende de cada programador. Você pode usá-los para grupos de peças relacionados logicamente do código, mas você não precisa fazê-los. Os arquivos são como as gavetas de uma cômoda, você pode colocar suas meias em uma gaveta, roupa intima em outra, e assim por diante, ou você pode usar um outro esquema de organização ou simplesmente optar por misturar tudo.

 O acesso a métodos:É conveniente pensar em métodos como sendo parte de um objeto, assim como as variáveis ​​de instância são. Como na figura abaixo:

 

 

 

 Métodos podem ser diagramados em torno das variáveis de instância dos objetos. Mas os métodos não são agrupados com as variáveis de instancia na memória. A memória é alocada para as instancias de variáveis de cada novo objeto, mas não há necessidade de alocar memória para métodos. Todas as instâncias precisão ter acesso aos métodos, em todas as instancias da mesma classe compartilham o acesso ao mesmo conjunto de métodos. Há apenas uma cópia dos métodos na memória, não importa quantas instâncias da classe são criadas.

 Linguagens de programação orientadas a objeto suportam o uso de conteiners de arquivo de código-fonte, mas também adicionam um módulo lógicoa para a linguagem — definições de classe. Como seria de esperar, é frequente que cada classe é definida em seu próprio arquivo fonte — módulos lógicos são associados a os módulos de contêiners.

 Em Objective-C, por exemplo, seria possível determinar qual a parte da classe Válvula que interage com os objetos Cano no mesmo arquivo que define a classe Cano, criando assim um módulo recipiente para o código de Canos relacionados e dividindo a classe Válvula em mais de um arquivo. A definição de classe Válvula ainda atuaria como uma unidade modular na construção do programa — ainda assim seria um módulo de lógica — não importando quantos arquivos do código-fonte foi localizado.

 Os mecanismos que fazem definições de classes unidades lógicas da linguagem são discutidos em detalhes em “Mecanismos de abstração.”

Reusabilidades

 O principal objetivo da programação orientada a objeto é fazer o código que você escreve reusável na medida do possível — para que ele possa servir a diversas situaçãoes e aplicações — de modo que você não precise reimplementar, mesmo que seja somente um pouco diferente de algo que já tenha feito.

 Reutilização é influenciada por fatores como estes:

  • Quão confiável e livre de bugs do código é;
  • Quão clara a documentação é;
  • Como simples e direta a interface de programação é;
  • Como eficientemente o código executa suas tarefas;
  • Quão completa o conjunto de recursos é;


Estes fatores não são aplicados somente no modelo do objeto. Eles podem ser usado para avaliar a reutilização de qualquer código — funções padrão C assim como definições de classes. Funções eficientes e bem documentadas, por exemplo, seria mais reutilizável que os não-documentados e não confiáveis.

 No entanto, uma comparação geral iria mostrar que as definições de classe prestam-se a um código reutilizável de forma que as funções não. Existem várias coisas que você pode fazer para tornar mais funções reutilizável, por exemplo, a passagem de dados como parâmetros em vez de assumir as variáveis ​​globais especificamente nomeados. Mesmo assim, verifica-se que apenas um pequeno subconjunto de funções pode ser generalizada além das aplicações que foram originalmente projetados para ela. A sua reutilização é inerentemente limitado pelo menos em três formas:

  • Os nomes das funções são globais; cada função deve ter um único nome (exceto para aqueles declarados como static). Esta exigência de nomenclatura torna difícil depender da biblioteca de código na construção de um sistema complexo. A interface de programação seria difícil de aprender e tão extensa que não poderia facilmente capturar generalizações significativas.
   
    Classes por outro lado, podem compartilhar interfaces. Quando a mesma convenção de nomenclatura é usado mais e mais, uma grande quantia de funcionalidades poderia ser empacotada dentro de um relativo pequeno e fácil modo de compreender a interface.

  • As funções são selecionadas a partir de uma biblioteca de um de cada vez. Cabe ao programador para pegar e escolher as funções individuais que necessitam.

Em contraste, os objetos vêm em pacotes de funcionalidade, e não como métodos individuais e variáveis ​​de instância. Eles fornecem serviços integrados, para que os usuários de uma biblioteca orientada a objetos não se atolem reunindo suas próprias soluções para um problema.

  • As funções são normalmente ligados a determinados tipos de estruturas de dados concebidas para um programa específico. A interação entre dados e função é uma parte inevitável da interface. A função é útil apenas para aqueles que concordam em utilizar o mesmo tipo de estruturas de dados que aceita como parâmetros.

Por isso ele esconde seus dados, um objeto não tem esse problema. Esta é uma das principais razões pelas quais as classes podem ser reutilizados mais facilmente do que as funções.

   Dados de um objeto são protegidos e não são tocados por qualquer outra parte do programa. Métodos podem, portanto, dar credibilidade na sua integridade. Eles podem ter certeza de que o acesso externo não colocaria os dados em um estado ilógico ou insustentável. Como resultado, uma estrutura de dados de objecto é mais confiável do que é passado por uma função, e os métodos podem depender mais. Métodos reutilizáveis ​​são, consequentemente, mais fácil de escrever.

 Além disso, como os dados de um objeto estão ocultos, uma classe pode ser reimplementada para usar uma estrutura de dados diferente, sem afetar sua interface. Todos os programas que usam a classe pode pegar a nova versão, sem alterar qualquer código-fonte, sem reprogramação necessária.

Mecanismos de Abstração

 Até este ponto, os objetos foram introduzidos como unidades que incorporam abstrações de nível superior e tão coerente role-players dentro de um aplicativo. No entanto, eles não podem ser utilizados desta maneira, sem o apoio de vários mecanismos de linguagem. Dois dos mecanismos mais importantes são o encapsulamento e polimorfismo.

 Encapsulamento mantêm a implementação de um objeto fora de sua interface, e Polimorfismo resulta a partir de dar a cada classe o seu próprio namespace. As seções a seguir discutem cada um desses mecanismos de cada vez.

Encapsulamento

 Para projetar efetivamente em qualquer nível de abstração, você precisa ser capaz de deixar os detalhes de implementação para trás e pensar em termos de unidades que agrupam esses detalhes em uma interface comum. Para que uma unidade de programação seja verdadeiramente eficaz, a barreira entre a interface e a implementação deve ser absoluta. A interface deve encapsular a implementação, isto é, escondê-lo de outras partes do programa. O Encapsulamento protege uma implementação de ações indesejadas e de acesso inadvertido.

 Em C, uma função é claramente encapsulada; a sua implementação é inacessível para outras do programa e protegida de qualquer ação que possa ser feita fora do da função. Em Objc-C implementações de métodos são parecidos com encapsulamentos, mas o mais importante são as instâncias de variáveis de um objeto. Elas estão escondidas dentro do objeto e invisíveis para o lado de fora. O encapsulamento de instancias de varáveis é as vezes chamada de informação oculta.

 Pôde parecer, à primeira vista, que esconder a informação em variáveis ​​de instância pode limitar a sua liberdade como um programador. Na verdade, isso irá lhe dar mais espaço para agir e libertá-lo das restrições que poderiam ser impostas. Se qualquer parte da implementação de um objeto puder vazar e se tornar acessível ou se tornar uma preocupação para outras partes ou programa (Interagir com outras partes, se tornando parte delas), isso irá amarrar as mãos tanto do implementador do objeto e de quem usaria o objeto. Nenhum deles poderá fazer modificações sem primeiro verificar com a outra parte do programa.

 Suponha, por exemplo, que você está interessado no objeto Torneira sendo desenvolvido para o programa que modela o uso de água, e quer incorporá-lo em outro programa que você está escrevendo. Uma vez que a interface para o objeto seja decidida, você não precisa se preocupar quando os outros trabalharem com ele, corrigir erros, e encontrar melhores maneiras de implementá-lo. Você recebe o benefício dessas melhorias, mas nenhum deles afeta o que você faz em seu programa. Porque você depende apenas da interface, nada que eles fazem pode quebrar seu código. Seu programa está isolada da implementação do objeto.

 Além disso, aqueles que implementam o objeto Torneira podem se interessar em como você usa a classe e possa tentar si certificar de que atende às suas necessidades, eles não têm que se preocupar com a forma como você escreveu o código. Nada que você possa fazer pode tocar a implementação do objeto ou limitar a sua liberdade de fazer mudanças de implementação em versões futuras. A implementação está isolada de qualquer coisa que você ou outros usuários do objeto pode fazer.

Poliformismo

 A habilidade de diferentes objetos responderem, cada um do seu próprio modo, a mensagens idênticas é chamado de poliformismo.

Poliformismo resulta do fato que cada classe vive em seu próprio namespace. Os nomes declarados dentro da classe não conflitam com nomes declarados em qualquer outro lugar fora dela. Isto é válido tanto para as variáveis de instância de um objeto, estrutura de dados e métodos de objetos:
  • Assim como os campos de uma estrutura C estão em um espaço protegido(namespace), assim são as variáveis ​​de instância de um objeto.

  • Os nomes dos métodos também são protegidos. Ao contrário dos nomes de funções C, nomes de métodos não são símbolos globais. O nome de um método em uma classe não pode entra em conflito com nomes de métodos em outras classes; duas classes muito diferentes podem implementar métodos com nomes idênticos.

   Nomes de métodos são parte da interface do objeto. Quando uma mensagem é enviada requisitando que um objeto faça algo, a mensagem menciona o nome do método que o objeto deve executar. Portanto diferentes objetos podem possuir métodos com o mesmo nome, o significado de uma mensagem deve ser de compreensão relativa ao objeto particular que recebe a mensagem. A mesma mensagem caso enviada para dois objetos diferentes com invocar dois métodos distintos.

O principal benefício do poliformismo é que isso simplifica a programação da interface. Permitindo convenções para se estabelecer que pode ser reutilizado em uma classe após a outra.

 SOBRECARGA: Os termos POLIFORMISMO e o parâmetro SOBRECARGA referem-se basicamente a mesma coisa, mas a partir de pontos de vista diferentes. Polimorfismo tem um ponto de vista pluralista e observa que várias classes de cada um pode ter um método com o mesmo nome. Parâmetro de sobrecarga toma o ponto de vista do nome do método e observa que ele pode produzir resultados diferentes, dependendo dos parâmetros passados ​​a ele. O operador de sobrecarga é semelhante. Isso se refere a habilidade de tornar operadores de uma linguagem (tal como == e + em C) em métodos que podem ser declarados com siginificados paritulares para tipos de objetos particulares. Objective-C implementa polimorfismo dos nomes dos métodos, mas não dos parâmetro ou sobrecarga de operadores.

 Por exemplo, suponha que você queira informar a quantidade de água utilizada por um objeto Electrodoméstico durante um determinado período de tempo. Em vez de definir um método montanteConsumido para a classe Electrodoméstico, um método montanteDisperçadoPelaTorneira para uma classe Torneira, e um método usoCumulativo para uma classe Construção, você pode simplesmente definir um método aguaUsada para cada classe. Esta consolidação reduz o número de métodos utilizados para o que é conceptualmente a mesma operação.

   Poliformismo permite ao código ser isolado em métodos de diferentes objetos, em vez de serem reunidos em uma única função que enumera todos os possíveis casos. Isso torna o código que você escreve mais extenso e reutilizável. Quando um novo caso surge, você não terá que reimplementar todo o código já existente; você precisará somente adicionar uma nova classe que com um novo método, deixando o código que já foi escrito intacto.

Por exemplo, suponha que você tenha um código que envia uma mensagem empate para um objeto. Dependendo do receptor a mensagem poderá produzir uma de duas possíveis quadros. Quando você quiser um terceiro caso, você não terá que mudar a mensagem ou alterar o código já escrito; você simplesmente permitirá que outro objeto seja declarado como receptor da mensagem.

Hierarquia

  A forma mais fácil de aprender algo novo é começando com algo que já entendemos. Se você quiser descrever o que é uma escuna, ajudaria se o seu ouvinte já conhece o que é um barco a vela. Se você quiser explicar como cravo funciona, seria melhor se você pode assumir que o seu público já olhou dentro de um piano, ou viu uma guitarra tocada, ou pelo menos está familiarizado com a idéia de um instrumento musical.

 O mesmo é válido se você quiser definir um novo tipo de objeto; a descrição é simples se a definição começar a partir de um objeto que já existe.

 Com este pensamento, linguagens de programação orientada a objetos permitem a você basear a definição de uma nova classe em uma classe que já foi definida. A base da classe é chamada de superclasse; a nova classe é uma subclasse. A definição da subclasse especifica somente como ela se diferencia da sua superclasse; todo o resto é considerado como sendo o mesmo.

   Nada é copiado da superclasse para a subclasse. Ao invés disso, as duas classes são conectadas de modo que a subclasse herda todos os métodos e variáveis de instância da sua superclasse, tal como você quer que seu ouvinte já entenda de escuna herdando o que eles já sabem sobre veleiros. Se a subclasse for definida vazia (se ela não define nenhuma variável de instancia ou seus próprios métodos), as duas classes serão idênticas (exceto os seus nomes)  e devem compartilhar a mesma definição. Seria o mesmo que explicar o que é uma rabeca dizendo que é exatamente como um violino. No entanto, a razão para declarar uma subclasse é não gerar sinônimos, mas para criar algo, no mínimo, um pouco diferente da sua superclasse. Por exemplo, você pode estender o comportamento de uma rabeca para algo que permita você executar músicas do gênero bluegrass em adição a música clássica.


Hierarquias de Classes

 

Qualquer classe pode ser usada como uma superclasse para uma nova definição de classe. Uma classe pode simultaneamente ser uma subclasse de outra classe, e uma superclasse para as suas próprias subclasses. Qualquer quantidade de classes pode desta maneira serem ligados em uma hierarquia de herança, assim como retratado abaixo:
Toda hierarquia de herança começa com uma classe raiz (root) que não possui uma superclasse. A partir da classe raiz, a hierarquia segue em ramos descendentes.Cada classe herda da sua superclasse e, através de sua superclasse, de todas as classes acima na hierarquia. Cada classe herda da classe raiz.
Cada classe é o acúmulo de todas as classes definidas em sua cadeia de herança. Um exemplo sobre isso, a classe D herda da classe C (esta sendo sua superclasse)  e também da classe raiz. Os membros da classe D possuem métodos e instancias de variáveis definidos em todas as três classes — D, C e na raiz.

 Tipicamente, cada classe possui somente uma superclasse e pode ter um ilimitado número de subclasses. No entanto, em linguagens de programação orientada a objetos (embora não em Objectice-C), uma classe pode ter mais do que uma superclasse; ele pode herdar através de múltiplas fontes. Em vez de ter uma única hierarquia que se ramifica descendentemente, como mostrado na figura anterior, herança múltipla permite que alguns ramos da hierarquia (ou de hierarquias diferentes) se fundem.


Definindo uma Subclasse

 Uma subclasse pode causar três tipos de mudanças em uma definição herdando através de uma superclasse:

  • Pode expandir a definição da classe que herda, adicionando novos métodos e variáveis ​​de instância. Este é o motivo mais comum para definir uma subclasse. Subclasses sempre adicionam novos métodos e adicionam novas variáveis ​​de instância, se os métodos exigem.

  • Ela pode modificar o comportamento herdado substituindo um método existente com uma nova versão. Isto é feito simplesmente pela implementação de um novo método com o mesmo nome que um que é herdado. A nova versão substitui a versão herdada. (O método herdado não desaparece, é ainda válido para a classe que o definiu e outras classes que herdam-no.)

  • Ela pode refinar ou estender o comportamento herdado substituindo um método existente com uma nova versão, mas ainda mantém a antiga versão, incorporando-o no novo método. Uma subclasse envia uma mensagem para executar a versão antiga no corpo do novo método. Cada classe em uma cadeia de herança pode contribuir parte do comportamento de um método. Na Figura acima sobre hierarquia, por exemplo, a classe D pode substituir um método definido na classe C e incorporar a versão de C, enquanto a versão de C incorpora uma versão definida na classe raiz.

  Subclasses, portanto, tendem a preencher a definição da superclasse, tornando-o mais específico e especializado. Eles acrescentam, e às vezes substituem, o código ao invés de subtrair. Nota-se que os métodos geralmente não podem ser deserdados e variáveis ​​de instância não podem ser removidas ou substituídas.

Usos da Herança

 Os exemplos clássicos de uma hierarquia de herança são emprestadas de taxonomias animal e vegetal. Por exemplo, poderia haver uma classe correspondente ao Pinaceae (pinheiro), da família das árvores. Suas subclasses podem ser Abeto, Pinho, Hemlock, Tamarack, DouglasFir e TrueCedar, correspondendo aos vários gêneros que compõem a família. A classe Pinho pode ter as subclasses Pinho Mole e Pinho Duro, com Pinho Branco, Pinho Doce e Pinho cerdas de Cone como subclasses de Pinho Mole e PonderosaPine, Jackpine, MontereyPine e Redpine como subclasses de Pinho Duro.

Raramente há um motivo para programar uma taxonomia como esta, mas a analogia é uma boa. Subclasses tendem a especializar-se uma superclasse ou adaptá-la a um propósito específico, assim como uma espécie especializa um gênero.

 Aqui estão alguns usos típicos de herança:

 Reutilização de código. Se duas ou mais classes têm algumas coisas em comum, mas também diferem em alguns aspectos, os elementos comuns podem ser colocados em uma única definição de classe que as outras classes herdam. O código comum é compartilhado e só precisam ser implementadas imediatamente.

  • Criação de um protocolo. Uma classe pode declarar um número de métodos onde é esperado que suas subclasses implementem o método. A classe pode ter as versões vazias dos métodos, ou pode implementar as versões parciais que são para ser incorporados nos métodos da subclasse. Em qualquer caso, as suas declarações estabelecem um protocolo que todas as suas subclasses devem seguir.

Quando diferentes classes implementam métodos com nome idênticos, um programa tem  melhor capacidade de fazer uso de poliformismo na sua concepção. A criação de um protocolo que subclasses devem implementar ajuda a reforçar essas convenções.

  • Oferecendo funcionalidade genérica. Um implementador pode definir uma classe que contenha um pouco do básico, um código geral para resolver alguns problemas, mas que não preencha todos os detalhes. Outros implementadores podem então criar uma subclasse para adaptar a classe genérica às suas necessidades específicas. Por exemplo, a classe Eletrodoméstico no programa que modela o uso da água poderá definir um  dispositivo de uso-de-água genérico, onde as subclasses iriam se transformar em tipos específicos de aparelhos eletrodomésticos.
A herança é tanto um modo de fazer alguém programar tarefas facilmente e um modo de separar levels da implementação.

  • Fazer pequenas modificações. Quando a herança é usada para fornecer uma funcionalidade genérica, criar um protocolo, ou reutiliza o código, uma classe é planejada de modo que é esperado que outras classes herdem dela. Mas você também pode usar a herança para modificar as classes que não se destinam a superclasses. Suponha, por exemplo, que há um objeto que iria funcionar bem em seu programa, mas você gostaria de mudar uma ou duas coisas que ele faz. Você pode fazer as mudanças em uma subclasse.

  • Prevendo possibilidades. Subclasses também podem ser usadas para fabricar alternativas para fins de teste. Por exemplo, se uma classe deve ser codificada com uma interface de usuário particular, interfaces alternativas podem ser divididas em subclasses durante a fase de designe do projeto. Cada alternativa pode então ser demostrada para um ususário potencial para ver qual ele prefere. Quando a escolha é feita, a subclasse selecionada pode ser reintegrada para sua superclasse.

Dinamismo

 Em um momento da história da programação, a questão de quanta memória um programa pode usar normalmente foi resolvida quando o código fonte foi compilado e ligado. Toda a memória que o programa poderia precisar estava reservado para ele uma vez que lançado. Esta memória foi fixada; não podendo ser diminuída ou aumentada.

 Em retrospectiva, isso evidentemente foi uma restrição gravíssima. Isso limita não somente como os programas são construídos, mas como você poderá imaginar um programa fazendo. Isso limita o designe, não apenas as técnicas de programação. A introdução de funções que alocam dinâmicamente a memória com um programa em execução (assim como malloc) abriram possibilidades que antes não existiam.

 As restrições de Compile-time e link-time  são limitadas por que elas forçam que as questões sejam decididas a partir de informações encontradas no código fonte do programador, em vez de a partir de informações obtidas do usuário com o programa em execução.

 Embora a alocação dinâmica remove algumas restrições, muitas outras, igualmente como a limitação de alocação estática de memória permanece. Por exemplo, os elementos que compõem um aplicativo devem ser correspondentes aos tipos de dados em tempo de compilação (compile-time). E os limites de uma aplicação são tipicamente determinados em tempo de ligação (link-time). Cada parte da aplicação deve ser unificada em um unico arquivo executável. Novos módulos e novos tipo não podem ser introduzidos com o programa em execução.

Objective-C visa superar essas limitações e fazer programas dinâmicos e fluídicos possíveis.  
Ela muda muito do peso da decisão a partir do tempo de compilação e tempo de ligação até a execução. O objetivo é permitir que os usuários do programa decidir o que vai acontecer, ao invés de restringir suas ações artificialmente pelas demandas da linguagem e as necessidades do compilador e ligador.

 Três tipos de dinamismos são especialmente importantes para a o designe da programação orientada a objeto:

  • Tipagem Dinâmica(Dynamic typing), aguardar até a execução para determinar a classe de um objeto
  • Ligação Dinâmica (Dynamic binding), determina até a execução qual método será invocado
  • Carregamento Dinâmico(Dynamic loading), adiciona novos componentes para um programa

Tipagem Dinâmica

 O compilador normalmente falha se o código que você escreve atribui um valor a um tipo que não pode acomodá-lo. Você pode ver avisos como estes:

 incompatible types in assignment

assignment of integer from pointer lacks a cast

 tradução:     “tipos incompatíveis na atribuição

atribuição de número inteiro de ponteiro não tem um cast”

   Verificação de tipo é útil, mas há momentos em que ele pode interferir com os benefícios que você que vem do polimorfismo, especialmente se o tipo de cada objeto devem ser conhecidos para o compilador.

 Suponha, por exemplo, que você quer enviar uma mensagem de um objeto para executar o método start. Como outros elementos de dados, o objecto é representado por uma variável. Se o tipo de variável (sua classe) deve ser conhecido em tempo de compilação, seria impossível deixar fatores de execução influenciar na decisão sobre o tipo de objeto que deve ser atribuído à variável. Se a classe da variável é fixada em código-fonte, por isso é a versão de start, que a mensagem invoca.

 Se, por outro lado, é possível esperar até a execução para descobrir a classe da variável, qualquer tipo de objeto pode ser atribuído a ele. Dependendo da classe do receptor, a mensagem de start pode invocar diferentes versões do método e produzir resultados muito diferentes.

 Tipagem dinâmica fornece assim substância à ligação dinâmica (discutido a seguir). Mas ele faz mais do que isso. Ele permite que as associações entre os objetos sejam determinadas em tempo de execução, ao invés de forçá-los a ser codificado em um projeto estático. Por exemplo, uma mensagem pode passar um objeto como um parâmetro sem declarar exatamente que tipo de objeto é, isto é, sem declarar sua classe. O receptor da mensagem pode, em seguida, enviar suas próprias mensagens para o objeto, uma vez mais, sem nunca se preocupar com o tipo de objeto que é. Porque o receptor usa o objeto passado para fazer parte de seu trabalho, ele é em sentido, personalizado por um objeto do tipo indeterminado (indeterminado no código-fonte, ou seja, não em tempo de execução).

 Ligação Dinâmica (Dynamic Binding)

 Em C padrão, você pode declarar um conjunto de funções alternativas, tal como as funções de string-comparison,

 int strcmp(const char *, const char *); // (Sensivel a letras Maiusculas ou Minusculas)

 int strcasecmp(const char *, const char *); //(Não Sensivel a letras Maiusculas ou Minusculas)

 e declara um ponteiro para uma função que possui o mesmo tipo de retorno e parâmetro :

 int (* compare)(const char *, const char*);

 Você pode então esperar até a execução para determinar qual função a ser atribuído ao ponteiro,

 if ( **argv == ‘i’)
   compare = strcasecmp;
else
    compare = srtcmp;

 e chamar a função através do ponteiro:

 if ( compare (s1,s2))

 

  Isto é semelhante ao que em programação orientada a objetos é chamado de ligação dinâmica, atrasando a decisão exata de qual método executar até que o programa está sendo executado.

 Embora nem todas as linguagens orientadas a objeto suportam isso, a ligação dinâmica pode ser realizada rotineiramente e de forma transparente através de mensagens. Você não precisa ter que passar pelo engano de declarar um ponteiro e atribuir valores a ele, como mostrado no exemplo acima. Você também não precisa atribuir a cada procedimento alternativo um nome diferente.

 Mensagens invocam métodos indiretamente. Toda expressão de mensagem deve encontrar um método de implementação para “chamar.” Para encontrar esse método, a máquina de mensagens deve verificar a classe do receptor e localizar sua implementação do método indicado na mensagem. Quando isto é feito em tempo de execução, o método é dinamicamente ligado à mensagem. Quando é feito pelo compilador, o método é estaticamente ligado.


Ligação Tardia: Algumas linguagens de programação orientadas a objeto (especialmente C + +) requer um receptor de mensagem a ser digitado estaticamente no código-fonte, mas não exigem o tipo para ser mais exato. O compilador, portanto não pode dizer se o receptor da mensagem é uma instância da classe especificada na declaração do tipo, uma instância de uma subclasse, ou uma instância de alguma classe derivada mais distante. Porque ele não sabe a classe exata do receptor, ele não pode saber qual a versão do método indicado na mensagem para invocar. Nesta circunstância, a escolha é entre tratar o receptor como se fosse uma instância da classe especificada e simplesmente ligar o método definido para essa classe da mensagem, ou esperar até algum momento posterior para resolver a situação. Em C + +, a decisão é adiada para conectar tempo para métodos (funções membro) que são declaradas virtualmente. Isso às vezes é designado como ligação tardia em vez de ligação dinâmica. Enquanto dinâmica no sentido de que isso acontece em tempo de execução, ele carrega consigo restrições de tipo de tempo de compilação rigorosas. Como discutido aqui (e implementado em Objective-C), ligação dinâmica é irrestrita.

Ligações dinâmicas são possíveis, mesmo na ausência de tipagem dinâmica, mas não é muito interessante. Há pouca vantagem em esperar até a execução para corresponder a um método para uma mensagem quando a classe do receptor é fixo e conhecido para o compilador. O compilador poderia muito bem encontrar o método em si, o resultado de execução não vai ser diferente.

 No entanto, se a classe do receptor é digitado de forma dinâmica, não há nenhuma maneira para o compilador para determinar qual o método a ser chamado. O método pode ser encontrado apenas depois que a classe do receptor seja resolvida em tempo de execução. Tipagem dinâmica implica, portanto, em ligação dinâmica.

 Tipagem dinâmica também torna ligação dinâmica interessante, pois abre a possibilidade de que uma mensagem pode ter resultados muito diferentes, dependendo da classe do receptor. Factores de tempo de execução podem influenciar a escolha do receptor e o resultado da mensagem.

Tipagem e ligação dinâmica também abrem a possibilidade de que o código que você escreverá pode enviar mensagens para os objetos ainda não inventados. Se os tipos de objeto não tem que ser decidido até a execução, você pode dar aos outros a liberdade para criar suas próprias classes e nomear seus próprios tipos de dados e ainda ter o seu código de enviar mensagens para seus objetos. Tudo o que você precisa aceitar estarão nas mensagens, e não os tipos de dados.

 Nota: A ligação dinâmica é rotina em Objective-C. Você não precisa organizar ela em especial, assim seu projeto não precisa se ​​preocupar com o que está sendo feito.

Carregamento Dinâmico(Dynamic loading)

 Historicamente, em muitos ambientes comuns, antes que um programa possa ser executado, todas as suas partes tiveram que ser ligados em um único arquivo. Quando é executado, o programa inteiro foi carregado na memória ao mesmo tempo.

 Alguns ambientes de programação orientada a objeto superararam esta limitação e permiti que diferentes partes de um programa executável a seja mantido em arquivos diferentes. O programa pode ser executado em pedaços assim que forem necessários. Cada peça é dinamicamente carregado e ligado com o resto do programa assim como ele foi executado. As ações do usuário podem determinar quais partes do programa estarão na memória e quais não estarão.

 Apenas o núcleo de um amplo programa necessita de ser colocado no início. Outros módulos podem ser adicionados conforme o usuário solicita os seus serviços. Módulos e usuários não solicitam nenhuma demanda de memória ao sistema.

 Carregamento dinâmico levanta possibilidades interessantes. Por exemplo, um programa inteiro não tem de ser desenvolvido de uma vez. Você pode entregar o seu software em pedaços e atualizar uma parte de cada vez. Você pode elaborar um programa que grupos de várias ferramentas em uma única interface, e carregar apenas as ferramentas que o usuário deseja. O programa pode até mesmo oferecer conjuntos de ferramentas alternativas para fazer o mesmo trabalho, o usuário seleciona uma ferramenta do conjunto e só essa ferramenta seria carregada.

 Talvez o mais importante benefício atual de carregamento dinâmico é que ele torna as aplicações extensíveis. Você pode permitir que outros possam adicionar e personalizar um programa que você projetou. Todo o seu programa precisa fazer é fornecer uma estrutura que os outros podem preencher, e, em tempo de execução, encontrar as peças que eles já implementaram e carregá-los dinamicamente.

 O principal desafio que é enfrentado pelo carregamento dinâmico é obter uma parte recém carregada de um programa para trabalhar com as peças já em execução, especialmente quando as diferentes partes foram escritas por pessoas diferentes. No entanto, grande parte desse problema desaparece em um ambiente orientado a objeto, pois o código é organizado em módulos lógicos com uma divisão clara entre implementação e interface. Quando as classes são carregadas dinamicamente, nada no código recém-carregado pode colidir com o código já existente. Cada classe encapsula a sua implementação e tem um namespace independente.

 Em adição, tipagem dinâmica e ligação dinâmica permitem classes projetadas por outros se encaixarem facilmente no programa que você projetou. Uma vez que a classe está carregada dinamicamente, ele é tratada de forma diferente de qualquer outra classe. Seu código pode enviar mensagens para seus objetos e os deles para a sua. Nenhum dos dois tem que saber o que a classe do outro tem implementado. Você só precisa de chegar a um acordo sobre um protocolo de comunicação.

 Carregamento e vinculação: Embora seja o termo comumente usado, carregamento dinâmico poderia muito bem ser chamado de ligação dinâmica. Programas estão ligados quando suas várias partes estão unidas para que eles possam trabalhar juntos, eles são carregados quando eles são lidos na memória volátil no momento da execução. Carregamento Dinâmico referece ao processo de separadamente carregar novos ou adicionar partes de um programa e ligá-los então dinâmicamente as partes já em execução.

Estruturação de Programas

 Programas orientados a objetos, tem dois tipos de estruturas. Uma pode ser vista em uma hierarquia de herança de classes definidas. A outra é evidenciada no fluxo de troda de mensagens como o programa é executado.

 A hierarquia de herança explica como os objetos estão relacionados por tipo. Por exemplo, no programa que os modelos de uso da água, pode acontecer que torneiras e canos são o mesmo tipo de objeto, a não ser que torneiras pode ser ligado e desligado e os tubos podem ter várias conexões com outras tubulações. Esta semelhança seria capturado na concepção do programa se as classes torneira e tubo herdar de uma superclasse comum.

  • A rede de ligações de objeto explica como funciona o programa. Por exemplo, objetos Eletrodoméstico podem enviar mensagens solicitando água para válvulas e as válvulas para tubos. Os Canos podem se comunicar com o objeto Construção, e o objeto Construção com todas as válvulas, torneiras e canos, mas não diretamente com Eletrodomésticos. Para comunicar-se uns com os outros, desta forma, os objetos devem saber sobre o outro. Um objeto Eletrodoméstico precisará de uma conexão com o objeto Válvula, e a Válvula com o objeto Cano, e assim por diante. Estas conexões definem a estrutura do programa.

 Programas orientados a objetos são projetados para expor a rede de objetos com os seus comportamentos e os padrões de interação e organizando a hierarquia das classes. Há estrutura, tanto na atividade do programa e na sua definição.

Conexões Outlet

 Parte da tarefa de projetar um programa orientado a objetos é organizar a rede de objetos. A rede não tem que ser estática; ela pode mudar dinamicamente conforme o programa é executado. Relações entre os objetos podem ser improvisados assim que necessário, eo tipo dos objetos, que desempenham funções atribuídas, podem mudar ao longo do tempo. Mas tem que haver um script.

 Algumas ligações podem ser totalmente transitório. Uma mensagem pode incluir um parâmetro de identificação de um objecto, talvez, o sender(rementente) da mensagem, de que o receptor é capaz de comunicar. Como ele responde a mensagem, o receptor pode enviar mensagens para o objeto, talvez identificando-se ou ainda um outro objeto, e que por sua vez pode se comunicar. Tais conexões são fugazes, duram apenas enquanto a cadeia de mensagens existir.

 Mas nem todas as conexões entre os objetos podem ser manipuladas em tempo real. Algumas precisam ser gravadas em estruturas de dados do programa. O quadro de conexões  dos objetos poderá ser mantido, ou poderá haver um serviço que identifica os objetos pelo nome. No entanto, a maneira mais simples é que cada objeto tenha variáveis ​​de instância que mantenha o controle dos outros objetos que ele deve se comunica. Estes variáveis ​​de instância, denominadas saídas porque elas gravam as saídas para mensagens, definirão as principais ligações entre os objetos na rede do programa.

 Embora os nomes das variáveis ​​de instância de saída (outlet) sejam arbitrárias, elas geralmente refletem os papéis que os objetos de saída (outlet) executam. Figura abaixo ilustra um objeto com quatro saídas(outlets), um agente, um amigo, um vizinho, e um chefe. Os objetos que desempenham essas partes podem mudar de vez em quando, mas as funções permanecem as mesmas.


Algumas saidas são definidas quando o objeto é inicializado pela primeira vez e nunca podem mudar. Outros podem ser definidas automaticamente como conseqüência de outras ações. Outros, ainda, podem ser definidos livremente, utilizando métodos fornecidos apenas para essa finalidade.

 Entretanto elas já estão configuradas, as variáveis de instancia outlet revelam a estrutura da aplicação. Ligam objectos numa rede de comunicação, bem como os componentes de um sistema de água estão ligadas pelas suas ligações físicas ou como os indivíduos são ligados pelos seus padrões de relações sociais.

Conexões Extrínsecas e Intrínsecas

 Conexões de Saída podem capturar diversos tipos de relações entre os objetos. Às vezes, as ligaçõe entre os objetos que se comunicam mais ou menos como parceiros iguais em um aplicativo, cada um com o seu próprio papel a desempenhar e não dominar o outro. Por exemplo, um objeto Eletrodoméstico pode ter uma variável de instância tomada para controlar a válvula que está conectada.

 Às vezes, um objeto deve ser visto como parte de um outro. Por exemplo, um objeto Torneira pode usar um objeto medidor para medir a quantidade de água que está sendo lançado. O objeto Medidor não teria qualquer outro objeto e agiria apenas sob ordens do objeto torneira. Seria uma parte intrínseca do objeto Torneira, em contraste com a ligação de um objecto extrínseca Eletrodoméstico um objeto da válvula.

 Da mesma forma, um objeto que supervisiona outros objetos pode manter uma lista de de suas tarefas. Um objeto Construção, por exemplo, pode ter uma lista de todos os objetos Canos no programa. Os objetos Canos seriam considerados uma parte intrínseca do objeto Construção e pertencem a ele. Objetos Canos, por outro lado, irão manter ligações extrínsecas para cada outros objetos.

Outlets Intrínsecos

Outlets intrínsecos comportam-se de maneira diferente das extrínsecas. Quando um objeto é liberado ou arquivado em um arquivo no disco, os objetos que estes intrínsecos Outlets apontam devem ser liberados ou salvos com ele. Por exemplo quando a Torneira é liberada, o seu medidor é inutilizado, portanto, e deverá ser também liberado. Uma torneira torneira arquivada sem o as medidas de uso seria de pouca utilidade quando for desarquivada( a menos que ela possa criar um novo objeto Medidor para ela mesma).

 Outlets Extrínsecos

 Outlets extrínsecos, por outro lado, capturam a organização do programa a um nível mais elevado. Elas registram as conexões entre subcomponentes do programa relativamente independentes. Quando um objeto Eletrodoméstico é liberado, o objeto Válvula que estava conectado continua a ser de uso e continua em vigor. Quando um objeto Eletrodoméstico está desarquivado, ele pode ser conectado a outro válvula e continuar a executar o mesmo tipo de papel que desempenhou antes.

Ativar da Rede de Objetos

 A rede de objetos é posto em movimento por um estímulo externo. Se você estiver escrevendo um aplicativo interativo com uma interface de usuário, ele irá responder às ações do usuário no teclado e mouse. Um programa que tenta fatorar números muito grandes pode começar quando você passar um número-alvo na linha de comando. Outros programas podem responder aos dados recebidos através de uma linha de telefone, as informações obtidas a partir de um banco de dados ou informações sobre o estado de um processo mecânico, através de um programa de monitoração.

 Programas geralmente são ativados por um fluxo de eventos, que está reportando uma atividade externa de algum tipo. Aplicações que exibem uma interface de usuário são movidos por eventos do teclado e mouse. Cada pressionar de uma tecla ou clique do mouse gera eventos que o aplicativo recebe e responde. Uma estrutura de programa orientada a objetos (uma rede de objetos que está preparado para responder a um estímulo externo) é ideal para este tipo de aplicação user-driven (conduzido pelo usuário).

Agregação e Decomposição

 Outra parte da tarefa de design é decidir o arranjo das classes – quando adicionar funcionalidades a uma classe existente, definindo uma subclasse e quando definir uma classe independente. O problema pode ser esclarecido ao imaginar o que aconteceria em caso extremo:

  • É possível conceber um programa que consiste em apenas um objeto. Porque é o único objeto, ele pode enviar mensagens apenas para si mesmo. Portanto, não pode tirar vantagem de polimorfismo, ou a modularidade de uma variedade de classes, ou um projeto de programa concebido como uma rede de Objetos interconectados. A verdadeira estrutura do programa estaria escondido dentro da definição de classe. Apesar de ter sido escrito em uma linguagem orientada a objetos, haveria muito pouco que foi orientada a objetos sobre ela.

  • Por outro lado, também é possível imaginar um programa que consiste em centenas de diferentes tipos de objectos, cada um com muito poucos métodos e funcionalidade limitada. Aqui, também, a estrutura do programa seria perdida, desta vez num labirinto de ligações de objectos.

 Obviamente, é melhor evitar qualquer um desses extremos, para manter os objetos grandes o suficiente para assumir um papel importante no programa, mas pequeno o suficiente para manter esse papel bem definido. A estrutura do programa deve ser fácil de entender no padrão de conexões de objetos.

 No entanto, a questão surge muitas vezes de se adicionar mais funcionalidades a uma classe ou a fatorar a funcionalidade adicional e colocá-lo em uma definição de classe separada. Por exemplo, um objeto Torneira precisa manter o controle de quanto de água está sendo usada ao longo do tempo. Para fazer isso, você poderia implementar os métodos necessários na classe Torneira, ou você pode inventar um objeto Medidor genérico para fazer o trabalho, como sugerido anteriormente. Cada objeto Torneira teria um outlet para conectá-lo a um objeto Medidor, e do medidor não interage com qualquer objeto, só com a torneira.

 A escolha muitas vezes depende de seus objetivos do projeto. Se o objeto Medidor pode ser usado em mais de uma situação, talvez totalmente em outro projeto, seria aumentar a reutilização de seu código para fatorar a tarefa de medição em uma classe separada. Se você tiver razões para fazer objetos Torneira como auto-suficiente quanto possível, a funcionalidade de medição pode ser adicionado à classe Torneira.

 Em geral, é melhor tentar para obter um código reutilizável e evitar ter grandes classes que fazem tantas coisas que eles não podem ser adaptadas a outras situações. Quando os objetos são concebidos como componentes, tornam-se muito mais reutilizáveis. O que funciona em um sistema ou configuração pode funcionar bem em outro.

 Dividir funcionalidade entre as diferentes classes, não necessariamente complicar a interface de programação. Se a classe de Torneira mantém o objeto Medidor particular, a interface Medidor não teria que ser publicado para os usuários da classe Torneira, o objeto seria tão escondido como qualquer outra variável de instância Torneira.

Modelos e Frameworks

 Objetos combinar estado e comportamento, e assim se assemelham a coisas no mundo real. Porque se assemelham a coisas reais, projetando um programa orientado a objetos é muito parecido a pensar de verdade as coisas, o que fazem, como eles funcionam, e como uma coisa está ligada a outra.

 Quando você cria um programa orientado a objeto, você está, de fato, montando uma simulação computadorizada de como a coisa funcionam. Redes de objetos se parecem e se comportam como modelos de sistemas reais. Um programa orientado a objeto pode ser pensado como um modelo, mesmo se não há nenhuma contrapartida real para ele no mundo real.

 Cada componente do modelo – cada tipo de objecto – é descrito em termos do seu comportamento, responsabilidades e interações com outros componentes. Porque a interface de um objeto está em seus métodos, não os seus dados, você pode começar o processo de design a pensar sobre o que um componente do sistema deve fazer, e não como ele é representado em dados. Uma vez que o comportamento de um objecto é decidido, a estrutura de dados adequado pode ser escolhida, mas isto é uma questão de aplicação, e não o desenho inicial.

 Por exemplo, no programa do uso da água, você não começaria por decidir como a estrutura de dados Torneira pareceria, mas o que você quer que um objeto Torneira faça – fazer uma conexão com um tubo, ser ligado e desligado, ajustar o taxa de fluxo, e assim por diante. O projeto, portanto, não é obrigado, desde o início pelas escolhas de dados. Você pode decidir sobre o comportamento do primeiro e implementar os dados depois. Sua escolha de estruturas de dados pode mudar ao longo do tempo, sem afetar o design.

 Projetando um programa orientado a objeto não implica necessariamente escrever grandes quantidades de código. A reutilização de definições de classes significa que a oportunidade é excelente para a construção de um programa em grande parte fora das classes elaboradas por outros. Pode até ser possível construir programas interessantes inteiramente fora das classes definidos por outra pessoa. Como o conjunto de definições de classe cresce, você tem mais e mais peças reutilizáveis ​​para escolher.

 Classes reutilizáveis vêm de muitas fontes. Projetos de desenvolvimento, muitas vezes produzem definições de classes reutilizáveis​​, e alguns desenvolvedores empreendedores os comercializa. Ambientes de programação orientadas a objeto normalmente vêm com bibliotecas de classe. Há bem mais de duas centenas de classes nas bibliotecas de Cocoa. Algumas dessas classes oferecem serviços básicos (hashing, armazenamento de dados, mensagens remoto). Outros são mais específicos (dispositivos de interface com o usuário, monitores de vídeo, som).

 Normalmente, um grupo de biblioteca de classes trabalham em conjunto para definir uma estrutura de programa parcial. Essas classes constituem uma estrutura de software (ou kit) que pode ser usado para construir uma variedade de diferentes tipos de aplicações. Quando você usa um framework, você aceita o modelo de programa que oferece e adapta seu projeto para ele. Você usa o framework por:

  • Inicializar e organizar as instâncias de classes do framework

  • Definindo subclasses de classes do framework

  • Definição de novas classes de sua preferência para trabalhar com classes definidas no framework

 Em cada um desses modos, você somente não adapta seu programa para o framework, mas você também adapta uma estrutura de framework genérica para especializá-la para fins específicos de sua aplicação.

 O framework, em essência, configura parte de uma rede de objetos para seu programa, e provê parte da sua hierarquia de classe. Seu próprio código completa um modelo de programa começado por um framework.

Estruturação da Tarefa de Programação

 Programar em seguindo programação orientada a objetos não somente estrutura os programas de uma melhor maneira, mas também ajuda a organizar as tarefas de programação.

 Como o software tenta fazer mais e mais, e os programas tornam-se maiores e mais complicados, o problema da gestão da tarefa também cresce. Há mais peças para encaixar juntos e mais pessoas trabalhando juntas para construí-los. A abordagem orientada a objectos oferece maneiras de lidar com esta complexidade, não apenas no desenho, mas também na organização do trabalho.

Colaboração

 Softwares complexos requerem uma esforço de colaboração extraordinário entre as pessoas que devem ser individualmente criativas, e ainda assim, tornar o que eles fazem se encaixar exatamente com o que os outros estão fazendo.

 O tamanho do esforço e do número de pessoas que trabalham no mesmo projeto ao mesmo tempo no mesmo lugar pode atrapalhar a capacidade do grupo para trabalhar cooperativamente em direção a um objetivo comum. Além disso, a colaboração é muitas vezes dificultada por barreiras de tempo, espaço e organização:

  • Código deve ser mantido, melhorado, e usado por muito tempo depois que ele escreveu. Os programadores que colaboram em um projeto não pode estar trabalhando nele ao mesmo tempo, de modo que não pode estar em uma posição para falar sobre as coisas e manter-se mutuamente informados sobre detalhes da implementação.

  • Mesmo que os programadores trabalham no mesmo projecto, ao mesmo tempo, eles não podem estar localizados no mesmo lugar. Isso também inibe o quão perto eles podem trabalhar juntos.

  • Os programadores que trabalham em diferentes grupos com diferentes prioridades e diferentes horários, muitas vezes deve colaborar em projetos. Comunicação através das barreiras organizacionais nem sempre é fácil de alcançar.

 A resposta a estas dificuldades devem crescer para fora da forma como os programas são concebidos e escritos. Isso não pode ser imposto de fora, na forma de estruturas de gestão e níveis hierárquicos rígidos de autoridade. Isto, muitas vezes atrapalha a criatividade das pessoas, e se tornam fardos em si mesmos. Em vez disso, a colaboração deve ser construída no próprio trabalho.

 É aí que as técnicas de programação orientada a objeto podem ajudar. Por exemplo, a reutilização de código orientado a objeto significa que os programadores podem colaborar de forma eficaz, mesmo quando trabalham em projetos diferentes em momentos diferentes ou em diferentes organizações, apenas através da partilha de seu código em bibliotecas. Este tipo de colaboração tem uma grande promessa, pois pode concebivelmente aliviar as tarefas difíceis e aparentemente impossíveis de fazer os projetos realizáveis

Organização de Projetos Orientados a Objetos

 Programação orientada a objetos ajuda a reestruturar a tarefa de programação de forma a beneficiar a colaboração. Ela ajuda a eliminar a necessidade de colaborar com baixo nível de detalhes de implementação, oferecendo estruturas que facilitam a colaboração em um nível superior. Quase todas as características do modelo de objeto, a partir da possibilidade de projetos de grande escala para o aumento da capacidade de reutilização de código, tem consequências para o modo como as pessoas trabalham em conjunto.

Projetando em Larga Escala

 Quando os programas são projetados em um alto nível de abstração, a divisão do trabalho é mais facilmente concebida. Pode combinar a divisão do programa em linhas lógicas, a forma como o projeto é organizado pode crescer fora de seu design.

 Com um design orientado a objeto, é mais fácil manter objetivos comuns à vista, ao invés de perdê-los na implementação, e mais fácil para que todos possam ver como a peça que está trabalhando se encaixa no todo. Seus esforços colaborativos são, portanto, mais susceptíveis de serem precisos.

Separando a Interface da Implementação

 As conexões entre os diversos componentes de um programa orientado a objetos são trabalhados no início do processo de design. Elas podem ser bem definidas, pelo menos para a fase inicial de desenvolvimento, antes do início da aplicação.

 Durante a implementação, apenas esta interface precisa ser coordenado, e a maioria dos que cai naturalmente fora do design. Como cada classe encapsula a sua implementação e tem seu próprio namespace, não há necessidade de coordenar detalhes de implementação. A colaboração é mais simples quando há menos exigências de coordenação.

Dividindo o Trabalho em Módulos

 A modularidade da programação orientada a objectos significa que os componentes lógicos de um amplo programa podem ser implementados cada um separadamente. Diferentes pessoas podem trabalhar em diferentes classes. Cada tarefa de aplicação é isolado dos outros.

Modularidade tem benefícios, não só para organizar a implementação, mas para corrigir problemas mais tarde. Porque implementações estão contidas dentro dos limites da classe, os problemas que surgem também são susceptíveis de ser isolados. É mais fácil rastrear os erros quando eles estão localizados em uma parte bem definida do programa.

 Separar responsabilidades por classe também significa que cada parte pode ser trabalhado por especialistas. Classes podem ser atualizados periodicamente para otimizar seu desempenho e fazer o melhor uso de novas tecnologias. Essas atualizações não tem que ser coordenadas com outras partes do programa. Contanto que a interface para um objeto não mude, as melhorias para a sua aplicação pode ser agendada a qualquer momento.

Mantendo a Interface Simples


O polimorfismo de programas orientados a objetos gera interfaces de programação mais simples, uma vez que os mesmos nomes e convenções podem ser reutilizados em qualquer número de classes. O resultado é aprender menos, uma maior compreensão compartilhada de como funciona todo o sistema, e um simples caminho para cooperação e colaboração.

Tomada de Decisões dinamicamente


Porque os programas orientados a objetos tomam decisões dinamicamente durante a execução, menos informação precisa ser fornecida em tempo de compilação (no código fonte) para fazer duas peças do código trabalhem em conjunto. Consequentemente, há menos de coordenar e menos para dar errado.

Herdando Código Genérico

   Herança é uma forma de reutilização de código. Se você pode definir suas classes como especializações das classes mais genéricas, a sua tarefa de programação é simplificado. O projeto é simplificado, bem como, uma vez que a hierarquia de herança estabelece as relações entre os diferentes níveis de implementação e os torna mais fáceis de entender.

   Herança também aumenta a reutilização ea confiabilidade do código. O código colocado numa superclasse é testada por suas subclasses. A classe genérica que você encontra em uma biblioteca terá sido testado por outras subclasses escritas por outros desenvolvedores para outras aplicações.

Reutilização de Código Testado

Tanto mais softwares que você puder tomar emprestado de outros e incorporar em seus próprios programas, a menos que você tenha que fazer sozinho é melhor para dinamizar a produção. Há mais software para emprestar em um ambiente de programação orientada a objeto, pois o código é mais reutilizável. A colaboração entre programadores que trabalham em lugares diferentes para diferentes organizações é reforçada, enquanto a carga de cada projeto é facilitado.

 Classes e estruturas de uma biblioteca orientada a objetos podem fazer contribuições substanciais para o seu programa. Quando você programa com as estruturas de software fornecidas pela Apple, por exemplo, você está efetivamente colaborar com os programadores da Apple, você está contraindo uma parte do seu programa, muitas vezes uma parte substancial, para eles. Você pode se concentrar no que você faz de melhor e deixar outras tarefas para o desenvolvedor biblioteca. Seus projetos podem ser um protótipo mais rápido, concluído mais rapidamente, com menos de um desafio colaborativo em seu próprio site.

O aumento da reutilização de código orientado a objeto também aumenta sua confiabilidade. A classe tirada de uma biblioteca é provável que tenha encontrado o seu caminho para uma variedade de aplicações e situações. Quanto mais o código tiver sido usado, o mais provável é que os problemas irão ter sido encontrado e corrigido. Erros que teriam parecido estranho e difícil de encontrar em seu programa já pode ter sido perseguidos e eliminados. Portando, lembrando a todos, esta tradução possui erros, portanto consultem a apostila original para suas próprias conclusões ou utilizem os links na na postagem  START!  aqui no blog.
Ainda preciso de ajuda para continuar a traduzir as apostilas. Conto com a ajuda de Vocês.

Este documento, não pode ser vendido, ou seder privilégios a ninguém!
Este documento é somente uma referência de estudos, não se trata de uma cópia ou tradução fiél ao documento original, onde me isento de qualquer responsabilidade, não assumindo nenhum risco de todo e qualquer dano ou problema causado por uma mal uso ou má interpretação do mesmo, servindo apenas como referencia de estudo. Portanto, é de extrema importância que entendam que este documento é livre e pode ser usado por qualquer um, editado ou copiado.

Portanto, ao baixar e seguir o conteúdo aqui registrado, você será a única pessoa responsável pelo mesmo.

Para aqueles que querem ajudar, a melhorar a tradução deste documento e ajudar em outras
entre em contato pelo email: tiagofly@hotmail.com.
Para quem tiver dúvidas além do blog também temos o Grupo de Estudo:
https://groups.google.com/d/forum/objectivecbrasil

Obrigado e Bons Estudos.

 Caso alguêm tenha dúvidas basta entrar : Grupo de Estudo Objective-C Brasil.
Para Referencias:  Apostila Original – Não Traduzida

Anúncios

2 comentários em “Apostila Programação Orientada a Objetos Objective C Traduzida PT BR

  1. Obrigado amigo!!! Agradaceço!!!

    Compartilhe com seus amigos, na faculdade ou no trabalho. Como eu sempre digo, conhecimento vale mais que dinheiro, e nunca é demais!

    Forte abraço, e bons estudos!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s