Aula (programação de computador) - Class (computer programming)

Na programação orientada a objetos , uma classe é um modelo de código de programa extensível para criar objetos , fornecendo valores iniciais para o estado ( variáveis ​​de membro ) e implementações de comportamento (funções ou métodos de membro ). Em muitas linguagens, o nome da classe é usado como o nome da classe (o próprio modelo), o nome do construtor padrão da classe (uma sub - rotina que cria objetos) e como o tipo de objeto gerado pela instanciação da classe; esses conceitos distintos são facilmente confundidos. Embora, a ponto de confluir, pode-se argumentar que é uma característica inerente a uma língua por causa de sua natureza polimórfica e porque essas línguas são tão poderosas, dinâmicas e adaptáveis ​​para uso em comparação com línguas sem polimorfismo presente. Assim, eles podem modelar sistemas dinâmicos (ou seja, o mundo real, aprendizado de máquina, IA) com mais facilidade.

Quando um objeto é criado por um construtor da classe, o objeto resultante é chamado de instância da classe e as variáveis ​​de membro específicas do objeto são chamadas de variáveis ​​de instância , para contrastar com as variáveis ​​de classe compartilhadas pela classe.

Em algumas linguagens, as classes são apenas um recurso de tempo de compilação (novas classes não podem ser declaradas em tempo de execução), enquanto em outras linguagens as classes são cidadãos de primeira classe e geralmente são eles próprios objetos (tipicamente do tipo Class ou similar). Nessas linguagens, uma classe que cria classes é chamada de metaclasse .

Classe vs. tipo

No uso casual, as pessoas geralmente se referem à "classe" de um objeto, mas os objetos estritamente falando têm tipo : a interface, ou seja, os tipos de variáveis ​​de membro, as assinaturas de funções de membro (métodos) e as propriedades que satisfazem. Ao mesmo tempo, uma classe tem uma implementação (especificamente a implementação dos métodos) e pode criar objetos de um determinado tipo, com uma determinada implementação. Nos termos da teoria dos tipos, uma classe é uma implementação‍ - ‌uma estrutura de dados concreta e coleção de sub-rotinas‍ - ‌enquanto um tipo é uma interface . Classes diferentes (concretas) podem produzir objetos do mesmo tipo (abstrato) (dependendo do sistema de tipos); por exemplo, o tipo Stack pode ser implementado com duas classes - SmallStack (rápido para pequenas pilhas, mas com baixa escalabilidade) e ScalableStack (escala bem, mas alta sobrecarga para pequenas pilhas). Da mesma forma, uma determinada classe pode ter vários construtores diferentes.

Os tipos de classe geralmente representam substantivos, como uma pessoa, lugar ou coisa, ou algo nominalizado , e uma classe representa uma implementação destes. Por exemplo, um Banana tipo pode representar as propriedades e funcionalidades de bananas em geral, enquanto os ABCBanana e XYZBanana aulas representaria formas de produção de bananas (por exemplo, fornecedores de bananas ou estruturas de dados e funções para representar e desenhar bananas em um jogo de vídeo). A classe ABCBanana poderia então produzir bananas específicas: as instâncias da classe ABCBanana seriam objetos do tipo Banana . Freqüentemente, apenas uma única implementação de um tipo é fornecida, caso em que o nome da classe é frequentemente idêntico ao nome do tipo.

Design e implementação

As aulas são compostas por componentes estruturais e comportamentais. Linguagens de programação que incluem classes como uma construção de programação oferecem suporte, para vários recursos relacionados a classes, e a sintaxe necessária para usar esses recursos varia muito de uma linguagem de programação para outra.

Estrutura

Notação UML para classes

Uma classe contém descrições de campos de dados (ou propriedades , campos , membros de dados ou atributos ). Geralmente, são tipos e nomes de campo que serão associados a variáveis ​​de estado no tempo de execução do programa; essas variáveis ​​de estado pertencem à classe ou a instâncias específicas da classe. Na maioria das linguagens, a estrutura definida pela classe determina o layout da memória usada por suas instâncias. Outras implementações são possíveis: por exemplo, objetos em Python usam contêineres de valor-chave associativo.

Algumas linguagens de programação, como Eiffel, oferecem suporte à especificação de invariantes como parte da definição da classe e as impõem por meio do sistema de tipos. O encapsulamento do estado é necessário para poder impor as invariantes da classe.

Comportamento

O comportamento da classe ou de suas instâncias é definido por meio de métodos . Métodos são sub - rotinas com a capacidade de operar em objetos ou classes. Essas operações podem alterar o estado de um objeto ou simplesmente fornecer maneiras de acessá-lo. Existem muitos tipos de métodos, mas o suporte para eles varia entre os idiomas. Alguns tipos de métodos são criados e chamados pelo código do programador, enquanto outros métodos especiais - como construtores, destruidores e operadores de conversão - são criados e chamados pelo código gerado pelo compilador. Uma linguagem também pode permitir que o programador defina e chame esses métodos especiais.

O conceito de interface de classe

Cada classe implementa (ou realiza ) uma interface fornecendo estrutura e comportamento. A estrutura consiste em dados e estado, e o comportamento consiste em código que especifica como os métodos são implementados. Há uma distinção entre a definição de uma interface e a implementação dessa interface; no entanto, essa linha é borrada em muitas linguagens de programação porque as declarações de classe definem e implementam uma interface. Algumas linguagens, entretanto, fornecem recursos que separam interface e implementação. Por exemplo, uma classe abstrata pode definir uma interface sem fornecer implementação.

As linguagens que oferecem suporte à herança de classes também permitem que as classes herdem interfaces das classes das quais são derivadas.

Por exemplo, se "classe A" herda de "classe B" e se "classe B" implementa a interface "interface B", então "classe A" também herda a funcionalidade (constantes e declaração de métodos) fornecida pela "interface B".

Em linguagens que suportam especificadores de acesso , a interface de uma classe é considerada o conjunto de membros públicos da classe, incluindo métodos e atributos (via métodos getter e setter implícitos ); quaisquer membros privados ou estruturas de dados internas não devem ser dependentes de código externo e, portanto, não fazem parte da interface.

A metodologia de programação orientada a objetos determina que as operações de qualquer interface de uma classe sejam independentes umas das outras. Isso resulta em um projeto em camadas onde os clientes de uma interface usam os métodos declarados na interface. Uma interface não impõe requisitos para que os clientes invoquem as operações de uma interface em qualquer ordem específica. Essa abordagem tem o benefício de que o código do cliente pode assumir que as operações de uma interface estão disponíveis para uso sempre que o cliente tiver acesso ao objeto.

Exemplo

Os botões na frente de seu aparelho de televisão são a interface entre você e a fiação elétrica do outro lado de sua caixa de plástico. Você pressiona o botão "liga / desliga" para ligar e desligar a televisão. Neste exemplo, sua televisão em particular é a instância, cada método é representado por um botão e todos os botões juntos compõem a interface (outros aparelhos de televisão que são do mesmo modelo que o seu teriam a mesma interface). Em sua forma mais comum, uma interface é uma especificação de um grupo de métodos relacionados sem qualquer implementação associada dos métodos.

Um aparelho de televisão também tem uma miríade de atributos , como tamanho e se suporta cores, que juntos formam sua estrutura. Uma classe representa a descrição completa de uma televisão, incluindo seus atributos (estrutura) e botões (interface).

Obter o número total de televisores fabricados pode ser um método estático da classe de televisão. Esse método está claramente associado à classe, embora esteja fora do domínio de cada instância individual da classe. Um método estático que encontra uma instância particular fora do conjunto de todos os objetos de televisão é outro exemplo.

Acessibilidade de membros

O seguinte é um conjunto comum de especificadores de acesso :

  • Privado (ou privado de classe ) restringe o acesso à própria classe. Apenas os métodos que fazem parte da mesma classe podem acessar membros privados.
  • Protegido (ou protegido por classe ) permite que a própria classe e todas as suas subclasses acessem o membro.
  • Público significa que qualquer código pode acessar o membro por seu nome.

Embora muitas linguagens orientadas a objetos suportem os especificadores de acesso acima, sua semântica pode ser diferente.

O design orientado a objetos usa os especificadores de acesso em conjunto com o design cuidadoso de implementações de métodos públicos para impor invariantes de classe - restrições no estado dos objetos. Um uso comum de especificadores de acesso é separar os dados internos de uma classe de sua interface: a estrutura interna torna-se privada, enquanto métodos de acesso público podem ser usados ​​para inspecionar ou alterar esses dados privados.

Os especificadores de acesso não controlam necessariamente a visibilidade , pois mesmo os membros privados podem ser visíveis para o código externo do cliente. Em algumas linguagens, um membro inacessível mas visível pode ser referido em tempo de execução (por exemplo, por um ponteiro retornado de uma função de membro), mas uma tentativa de usá-lo referindo-se ao nome do membro do código do cliente será evitado pelo verificador de tipo.

As várias linguagens de programação orientadas a objetos reforçam a acessibilidade e a visibilidade dos membros em vários graus e, dependendo do sistema de tipos da linguagem e das políticas de compilação, aplicadas em tempo de compilação ou tempo de execução . Por exemplo, a linguagem Java não permite que o código do cliente que acessa os dados privados de uma classe seja compilado. Na linguagem C ++ , os métodos privados são visíveis, mas não acessíveis na interface; no entanto, eles podem se tornar invisíveis ao declarar explicitamente classes totalmente abstratas que representam as interfaces da classe.

Alguns idiomas apresentam outros esquemas de acessibilidade:

  • Instância acessibilidade classe vs. : Rubi suporta instância-privadas e protegidas por exemplo especificadores de acesso em vez de classe-privada e, respectivamente protegida de classe. Eles diferem porque restringem o acesso com base na própria instância, em vez de na classe da instância.
  • Amigo : C ++ suporta um mecanismo onde uma função declarada explicitamente como uma função amiga da classe pode acessar os membros designados como privados ou protegidos.
  • Baseado em caminho : Java oferece suporte à restrição de acesso a um membro em um pacote Java , que é o caminho lógico do arquivo. No entanto, é uma prática comum ao estender uma estrutura Java para implementar classes no mesmo pacote que uma classe de estrutura para acessar membros protegidos. O arquivo de origem pode existir em um local completamente diferente e pode ser implementado em um arquivo .jar diferente, mas ainda estar no mesmo caminho lógico no que diz respeito à JVM.

Relações entre classes

Além do projeto de classes autônomas, as linguagens de programação podem oferecer suporte a projetos de classes mais avançados com base nos relacionamentos entre as classes. Os recursos de design de relacionamento entre classes comumente fornecidos são composicionais e hierárquicos .

Composicional

As classes podem ser compostas por outras classes, estabelecendo assim um relacionamento de composição entre a classe envolvente e suas classes incorporadas. O relacionamento de composição entre classes também é comumente conhecido como um relacionamento tem-um . Por exemplo, uma classe "Carro" pode ser composta e conter uma classe "Motor". Portanto, um carro tem um motor. Um aspecto da composição é a contenção, que é o fechamento das instâncias do componente pela instância que os possui. Se um objeto envolvente contém instâncias de componente por valor, os componentes e seu objeto envolvente têm um tempo de vida semelhante . Se os componentes estiverem contidos por referência, eles podem não ter uma vida útil semelhante. Por exemplo, em Objective-C 2.0:

@interface Car : NSObject

@property NSString *name;
@property Engine *engine
@property NSArray *tires;

@end

Esta classe Car tem uma instância de NSString (um objeto string ), Engine e NSArray (um objeto array).

Hierárquico

As classes podem ser derivadas de uma ou mais classes existentes, estabelecendo assim uma relação hierárquica entre as classes derivadas ( classes base , classes pai ou superclasses ) e a classe derivada (classe filhaousubclasse). O relacionamento da classe derivada com as classes derivadas é comumente conhecido como um relacionamento é um . Por exemplo, uma classe 'Botão' pode ser derivada de uma classe 'Controle'. Portanto, um botãoé umcontrole. Os membros estruturais e comportamentais das classes pai sãoherdadospela classe filha. As classes derivadas podem definir membros estruturais (campos de dados) e membros comportamentais (métodos) adicionais, além daqueles queherdame, portanto, sãoespecializaçõesde suas superclasses. Além disso, as classes derivadas podemsubstituirmétodos herdados se a linguagem permitir.

Nem todos os idiomas oferecem suporte a herança múltipla. Por exemplo, Java permite que uma classe implemente várias interfaces, mas herde apenas de uma classe. Se a herança múltipla for permitida, a hierarquia é um gráfico acíclico direcionado (ou DAG para abreviar), caso contrário, é uma árvore . A hierarquia possui classes como nós e relacionamentos de herança como links. As classes no mesmo nível têm mais probabilidade de serem associadas do que as classes em níveis diferentes. Os níveis dessa hierarquia são chamados de camadas ou níveis de abstração .

Exemplo (código Objective-C 2.0 simplificado, do iPhone SDK):

@interface UIResponder : NSObject //...
@interface UIView : UIResponder //...
@interface UIScrollView : UIView //...
@interface UITableView : UIScrollView //...

Neste exemplo, um UITableView é um UIScrollView é um UIView é um UIResponder é um NSObject.

Definições de subclasse

Conceitualmente, uma superclasse é um superconjunto de suas subclasses. Por exemplo, uma hierarquia de classes comum envolveria GraphicObject como uma superclasse de Rectangle e Ellipse , enquanto Square seria uma subclasse de Rectangle . Essas são todas as relações de subconjunto na teoria dos conjuntos também, ou seja, todos os quadrados são retângulos, mas nem todos os retângulos são quadrados.

Um erro conceitual comum é confundir uma parte da relação com uma subclasse. Por exemplo, um carro e um caminhão são ambos tipos de veículos e seria apropriado modelá-los como subclasses de uma classe de veículo. No entanto, seria um erro modelar as partes componentes do carro como relações de subclasse. Por exemplo, um carro é composto de um motor e uma carroceria, mas não seria apropriado modelar o motor ou a carroceria como uma subclasse de carro.

Na modelagem orientada a objetos, esses tipos de relações são normalmente modelados como propriedades de objetos. Neste exemplo, a classe Car teria uma propriedade chamada parts . partes seriam digitadas para conter uma coleção de objetos, como instâncias de Body , Engine , Tires , etc. Linguagens de modelagem de objetos, como UML, incluem recursos para modelar vários aspectos de "parte de" e outros tipos de relações - dados como o cardinalidade dos objetos, restrições nos valores de entrada e saída, etc. Essas informações podem ser utilizadas por ferramentas de desenvolvedor para gerar código adicional ao lado das definições de dados básicos para os objetos, como verificação de erro nos métodos get e set .

Uma questão importante ao modelar e implementar um sistema de classes de objetos é se uma classe pode ter uma ou mais superclasses. No mundo real, com conjuntos reais, seria raro encontrar conjuntos que não se cruzassem com mais de um outro conjunto. No entanto, embora alguns sistemas como Flavors e CLOS forneçam a capacidade de mais de um pai fazer isso em tempo de execução, introduz uma complexidade que muitos na comunidade orientada a objetos consideram antitética aos objetivos de usar classes de objetos em primeiro lugar. Entender qual classe será responsável por lidar com uma mensagem pode se tornar complexo ao lidar com mais de uma superclasse. Se usado sem cuidado, esse recurso pode introduzir parte da mesma complexidade do sistema e as classes de ambigüidade foram projetadas para evitar.

A maioria das linguagens orientadas a objetos modernas, como Smalltalk e Java, requerem herança única em tempo de execução. Para essas linguagens, a herança múltipla pode ser útil para modelagem, mas não para uma implementação.

No entanto, os objetos de aplicativos da web semântica têm várias superclasses. A volatilidade da Internet requer esse nível de flexibilidade e os padrões de tecnologia como o Web Ontology Language (OWL) são projetados para suportá-lo.

Um problema semelhante é se a hierarquia de classes pode ou não ser modificada em tempo de execução. Linguagens como Flavors, CLOS e Smalltalk oferecem suporte a esse recurso como parte de seus protocolos de meta-objeto . Uma vez que as próprias classes são objetos de primeira classe, é possível fazer com que alterem dinamicamente sua estrutura, enviando-lhes as mensagens apropriadas. Outras linguagens que se concentram mais em tipagem forte, como Java e C ++, não permitem que a hierarquia de classes seja modificada em tempo de execução. Objetos da web semântica têm a capacidade de mudanças em tempo de execução para classes. A lógica é semelhante à justificativa para permitir superclasses múltiplas, de que a Internet é tão dinâmica e flexível que mudanças dinâmicas na hierarquia são necessárias para gerenciar essa volatilidade.

Ortogonalidade do conceito de classe e herança

Embora as linguagens baseadas em classes sejam comumente consideradas como compatíveis com herança, herança não é um aspecto intrínseco do conceito de classes. Algumas linguagens, frequentemente chamadas de " linguagens baseadas em objeto ", oferecem suporte a classes, mas não oferecem suporte à herança. Exemplos de linguagens baseadas em objeto incluem versões anteriores do Visual Basic .

Dentro da análise orientada a objetos

Na análise orientada a objetos e em UML , uma associação entre duas classes representa uma colaboração entre as classes ou suas instâncias correspondentes. As associações têm direção; por exemplo, uma associação bidirecional entre duas classes indica que ambas as classes estão cientes de seu relacionamento. As associações podem ser rotuladas de acordo com seu nome ou propósito.

Um papel de associação recebe o final de uma associação e descreve o papel da classe correspondente. Por exemplo, uma função de "assinante" descreve a maneira como as instâncias da classe "Pessoa" participam de uma associação "inscreve-se" com a classe "Revista". Além disso, uma "Revista" tem a função de "revista assinada" na mesma associação. A multiplicidade de papéis de associação descreve quantas instâncias correspondem a cada instância da outra classe da associação. As multiplicidades comuns são "0..1", "1..1", "1 .. *" e "0 .. *", onde o "*" especifica qualquer número de instâncias.

Taxonomia de classes

Existem muitas categorias de classes, algumas das quais se sobrepõem.

Abstrato e concreto

Em uma linguagem que suporta herança, uma classe abstrata , ou classe base abstrata (ABC), é uma classe que não pode ser instanciada porque é rotulada como abstrata ou simplesmente especifica métodos abstratos (ou métodos virtuais ). Uma classe abstrata pode fornecer implementações de alguns métodos e também pode especificar métodos virtuais por meio de assinaturas que devem ser implementadas por descendentes diretos ou indiretos da classe abstrata. Antes que uma classe derivada de uma classe abstrata possa ser instanciada, todos os métodos abstratos de suas classes pai devem ser implementados por alguma classe na cadeia de derivação.

A maioria das linguagens de programação orientadas a objetos permite que o programador especifique quais classes são consideradas abstratas e não permitem que sejam instanciadas. Por exemplo, em Java , C # e PHP , a palavra-chave abstract é usada. Em C ++ , uma classe abstrata é uma classe que tem pelo menos um método abstrato fornecido pela sintaxe apropriada nessa linguagem (uma função virtual pura na linguagem C ++).

Uma classe que consiste apenas em métodos virtuais é chamada de Pure Abstract Base Class (ou Pure ABC ) em C ++ e também é conhecida como uma interface pelos usuários da linguagem. Outras linguagens, notadamente Java e C #, oferecem suporte a uma variante de classes abstratas chamada interface por meio de uma palavra-chave na linguagem. Nessas linguagens, a herança múltipla não é permitida, mas uma classe pode implementar várias interfaces. Essa classe só pode conter métodos abstratos acessíveis ao público.

Uma classe concreta é uma classe que pode ser instanciada , ao contrário de classes abstratas, que não podem.

Local e interno

Em algumas linguagens, as classes podem ser declaradas em escopos diferentes do escopo global. Existem vários tipos dessas classes.

Uma classe interna é uma classe definida em outra classe. O relacionamento entre uma classe interna e sua classe contida também pode ser tratado como outro tipo de associação de classe. Uma classe interna normalmente não está associada a instâncias da classe delimitadora nem instanciada junto com sua classe delimitadora. Dependendo do idioma, pode ou não ser possível referir-se à classe de fora da classe envolvente. Um conceito relacionado são os tipos internos , também conhecidos como tipo de dados interno ou tipo aninhado , que é uma generalização do conceito de classes internas. C ++ é um exemplo de linguagem que oferece suporte a classes internas e tipos internos (por meio de declarações de typedef ).

Outro tipo é uma classe local , que é uma classe definida em um procedimento ou função. Isso limita as referências ao nome da classe dentro do escopo onde a classe é declarada. Dependendo das regras semânticas do idioma, pode haver restrições adicionais nas classes locais em comparação com as não locais. Uma restrição comum é impedir que métodos de classe locais acessem variáveis ​​locais da função envolvente. Por exemplo, em C ++, uma classe local pode se referir a variáveis ​​estáticas declaradas em sua função envolvente, mas não pode acessar as variáveis ​​automáticas da função .

Metaclasses

Metaclasses são classes cujas instâncias são classes. Uma metaclasse descreve uma estrutura comum de uma coleção de classes e pode implementar um padrão de design ou descrever tipos específicos de classes. Metaclasses são freqüentemente usadas para descrever frameworks .

Em algumas linguagens, como Python , Ruby ou Smalltalk , uma classe também é um objeto; portanto, cada classe é uma instância de uma metaclasse exclusiva que é construída na linguagem. O Common Lisp Object System (CLOS) fornece protocolos de metaobjetos (MOPs) para implementar essas classes e metaclasses.

Não subclassível

Classes não subclassíveis permitem que os programadores projetem classes e hierarquias de classes onde, em algum nível da hierarquia, derivação adicional é proibida (uma classe autônoma também pode ser designada como não subclassível, evitando a formação de qualquer hierarquia). Compare isso com as classes abstratas , que implicam, encorajam e requerem derivação para serem usadas. Uma classe não subclassível é implicitamente concreta .

Uma classe não subclassível é criada declarando a classe como sealedem C # ou como finalem Java ou PHP. Por exemplo, a Stringclasse de Java é designada como final .

Classes não subclassíveis podem permitir que um compilador (em linguagens compiladas) execute otimizações que não estão disponíveis para classes subclassíveis.

Aula aberta

Uma classe aberta é aquela que pode ser alterada. Normalmente, um programa executável não pode ser alterado pelos clientes. Os desenvolvedores geralmente podem alterar algumas classes, mas normalmente não podem alterar as classes padrão ou integradas. Em Ruby , todas as aulas são abertas. Em Python , as classes podem ser criadas em tempo de execução e todas podem ser modificadas posteriormente. As categorias Objective-C permitem ao programador adicionar métodos a uma classe existente sem a necessidade de recompilar essa classe ou mesmo ter acesso ao seu código-fonte.

Mixins

Algumas linguagens têm suporte especial para mixins , embora em qualquer linguagem com herança múltipla, um mixin é simplesmente uma classe que não representa um relacionamento é-um-tipo-de. Mixins são normalmente usados ​​para adicionar os mesmos métodos a várias classes; por exemplo, uma classe UnicodeConversionMixin pode fornecer um método chamado unicode_to_ascii quando incluído nas classes FileReader e WebPageScraper que não compartilham um pai comum.

Parcial

Em linguagens que oferecem suporte ao recurso, uma classe parcial é uma classe cuja definição pode ser dividida em várias partes, em um único arquivo de código-fonte ou em vários arquivos. As partes são mescladas em tempo de compilação, tornando a saída do compilador a mesma de uma classe não parcial.

A principal motivação para a introdução de classes parciais é facilitar a implementação de geradores de código , como designers visuais . Caso contrário, é um desafio ou compromisso desenvolver geradores de código que possam gerenciar o código gerado quando ele é intercalado no código escrito pelo desenvolvedor. Usando classes parciais, um gerador de código pode processar um arquivo separado ou classe parcial de granulação grossa dentro de um arquivo e, portanto, é aliviado da intrincada interjeição do código gerado por meio de análise extensa, aumentando a eficiência do compilador e eliminando o risco potencial de corromper o código do desenvolvedor. Em uma implementação simples de classes parciais, o compilador pode realizar uma fase de pré - compilação onde "unifica" todas as partes de uma classe parcial. Em seguida, a compilação pode prosseguir normalmente.

Outros benefícios e efeitos do recurso de classe parcial incluem:

  • Permite a separação da interface de uma classe e do código de implementação de uma maneira única.
  • Facilita a navegação por grandes classes em um editor .
  • Permite a separação de interesses , de maneira semelhante à programação orientada a aspectos, mas sem usar nenhuma ferramenta extra.
  • Permite que vários desenvolvedores trabalhem em uma única classe simultaneamente, sem a necessidade de mesclar código individual em um arquivo posteriormente.

Classes parciais existem em Smalltalk sob o nome de Class Extensions há um tempo considerável. Com a chegada do .NET framework 2 , a Microsoft introduziu classes parciais, com suporte em C # 2.0 e Visual Basic 2005 . O WinRT também oferece suporte a classes parciais.

Exemplo em VB.NET

Este exemplo simples, escrito em Visual Basic .NET , mostra como partes da mesma classe são definidas em dois arquivos diferentes.

file1.vb
Partial Class MyClass
    Private _name As String
End Class
file2.vb
Partial Class MyClass
    Public Readonly Property Name() As String
         Get
             Return _name
         End Get
    End Property
End Class

Quando compilado, o resultado é o mesmo como se os dois arquivos fossem gravados como um, como este:

Class MyClass
    Private _name As String
    Public Readonly Property Name() As String
         Get
             Return _name
         End Get
    End Property
End Class

Exemplo em Objective-C

Em Objective-C , classes parciais, também conhecidas como categorias , podem até mesmo se espalhar por várias bibliotecas e executáveis, como no exemplo a seguir. Mas uma diferença fundamental é que as categorias do Objective-C podem sobrescrever as definições em outra declaração de interface e que as categorias não são iguais à definição da classe original (a primeira requer a última). Em vez disso, a classe parcial .NET não pode ter definições conflitantes e todas as definições parciais são iguais às outras.

No Foundation, arquivo de cabeçalho NSData.h:

@interface NSData : NSObject

- (id)initWithContentsOfURL:(NSURL *)URL;
//...

@end

Na biblioteca fornecida pelo usuário, um binário separado da estrutura Foundation, arquivo de cabeçalho NSData + base64.h:

#import <Foundation/Foundation.h>

@interface NSData (base64)

- (NSString *)base64String;
- (id)initWithBase64String:(NSString *)base64String;

@end

E em um aplicativo, outro arquivo binário separado, arquivo de código-fonte main.m:

#import <Foundation/Foundation.h>
#import "NSData+base64.h"

int main(int argc, char *argv[])
{
    if (argc < 2)
        return EXIT_FAILURE;
    NSString *sourceURLString = [NSString stringWithCString:argv[1]];
    NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:sourceURLString]];
    NSLog(@"%@", [data base64String]);
    return EXIT_SUCCESS;
}

O despachante encontrará os dois métodos chamados na instância NSData e os chamará corretamente.

Iminstantível

As classes não instáveis permitem que os programadores agrupem campos e métodos por classe que são acessíveis em tempo de execução sem uma instância da classe. Na verdade, a instanciação é proibida para este tipo de classe.

Por exemplo, em C #, uma classe marcada como "estática" não pode ser instanciada, pode ter apenas membros estáticos (campos, métodos, outros), pode não ter construtores de instância e é lacrada .

Sem nome

Uma classe sem nome ou classe anônima é uma classe que não está vinculada a um nome ou identificador na definição. Isso é análogo a funções nomeadas versus funções não nomeadas .

Benefícios

Os benefícios de organizar o software em classes de objetos se enquadram em três categorias:

  • Desenvolvimento rápido
  • Facilidade de manutenção
  • Reutilização de código e designs

As classes de objeto facilitam o desenvolvimento rápido porque diminuem a lacuna semântica entre o código e os usuários. Os analistas de sistema podem conversar com desenvolvedores e usuários usando essencialmente o mesmo vocabulário, falando sobre contas, clientes, contas, etc. As classes de objetos geralmente facilitam o desenvolvimento rápido porque a maioria dos ambientes orientados a objetos vem com ferramentas poderosas de depuração e teste. As instâncias de classes podem ser inspecionadas em tempo de execução para verificar se o sistema está funcionando conforme o esperado. Além disso, em vez de obter despejos de memória central, a maioria dos ambientes orientados a objetos interpretou os recursos de depuração para que o desenvolvedor possa analisar exatamente onde ocorreu o erro no programa e ver quais métodos foram chamados para quais argumentos e com quais argumentos.

As classes de objetos facilitam a manutenção por meio do encapsulamento. Quando os desenvolvedores precisam mudar o comportamento de um objeto, eles podem localizar a mudança apenas para esse objeto e suas partes componentes. Isso reduz o potencial de efeitos colaterais indesejados dos aprimoramentos de manutenção.

A reutilização de software também é um grande benefício do uso de classes de objeto. As classes facilitam a reutilização por meio de herança e interfaces. Quando um novo comportamento é necessário, ele geralmente pode ser alcançado criando uma nova classe e fazendo com que essa classe herde os comportamentos e dados padrão de sua superclasse e, a seguir, adapte algum aspecto do comportamento ou dos dados de acordo. A reutilização por meio de interfaces (também conhecidas como métodos) ocorre quando outro objeto deseja invocar (em vez de criar um novo tipo de) alguma classe de objeto. Este método de reutilização remove muitos dos erros comuns que podem aparecer no software quando um programa reutiliza o código de outro.

Representação em tempo de execução

Como um tipo de dados, uma classe é geralmente considerada uma construção de tempo de compilação. Uma linguagem ou biblioteca também pode suportar protótipo ou meta- objetos de fábrica que representam informações de tempo de execução sobre classes, ou mesmo representam metadados que fornecem acesso a recursos de reflexão e capacidade de manipular formatos de estrutura de dados em tempo de execução. Muitas linguagens distinguem esse tipo de informação de tipo de tempo de execução sobre classes de uma classe com base no fato de que as informações não são necessárias em tempo de execução. Algumas linguagens dinâmicas não fazem distinções estritas entre construções de tempo de execução e de tempo de compilação e, portanto, podem não distinguir entre metaobjetos e classes.

Por exemplo, se Human é um metaobjeto que representa a classe Person, as instâncias da classe Person podem ser criadas usando os recursos do metaobjeto Humano .

Veja também

Notas

Referências

Leitura adicional