Na linguagem Java, classe abstrata e interface são dois mecanismos que suportam a definição de classe abstrata. É precisamente por causa da existência desses dois mecanismos que Java recebe poderosas capacidades de orientação a objetos. Existem grandes semelhanças entre classe abstrata e interface em termos de suporte para definição de classe abstrata, e elas podem até ser substituídas entre si. Portanto, muitos desenvolvedores parecem ser mais casuais na escolha da classe abstrata e da interface ao definir classes abstratas. Na verdade, ainda há uma grande diferença entre os dois. A escolha deles reflete até mesmo a compreensão da natureza do domínio do problema e se a compreensão da intenção do design é correta e razoável. Este artigo analisará as diferenças entre eles e tentará fornecer aos desenvolvedores uma base para escolher entre os dois.
Entenda classes abstratas
Classe abstrata e interface são usadas para definir classes abstratas na linguagem Java (a classe abstrata neste artigo não é traduzida da classe abstrata, ela representa um corpo abstrato, e a classe abstrata é usada para definir classes abstratas na linguagem Java) A método, preste atenção à distinção), então o que é uma classe abstrata e quais benefícios o uso de classes abstratas pode nos trazer?
No conceito orientado a objetos sabemos que todos os objetos são representados por classes, mas o inverso não é verdadeiro. Nem todas as classes são usadas para descrever objetos. Se uma classe não contém informações suficientes para descrever um objeto específico, tal classe é uma classe abstrata. Classes abstratas são frequentemente usadas para representar conceitos abstratos que derivamos da análise e do design de áreas problemáticas. Elas são abstrações de uma série de conceitos específicos que parecem diferentes, mas são essencialmente iguais. Por exemplo: Se desenvolvermos um software de edição gráfica, descobriremos que existem alguns conceitos específicos, como círculos e triângulos, no domínio do problema. Eles são diferentes, mas todos pertencem ao conceito de forma. no domínio do problema. Se existir, é um conceito abstrato. É precisamente porque os conceitos abstratos não possuem conceitos concretos correspondentes no domínio do problema, então as classes abstratas usadas para representar conceitos abstratos não podem ser instanciadas.
No campo orientado a objetos, as classes abstratas são usadas principalmente para ocultar tipos. Podemos construir uma descrição abstrata de um conjunto fixo de comportamentos, mas esse conjunto de comportamentos pode ter qualquer número de implementações concretas possíveis. Esta descrição abstrata é a classe abstrata, e este conjunto de quaisquer implementações concretas possíveis é representado por todas as classes derivadas possíveis. Os módulos podem operar em um corpo abstrato. Como um módulo depende de uma abstração fixa, ele não pode ser modificado ao mesmo tempo, o comportamento deste módulo também pode ser estendido derivando desta abstração; Os leitores familiarizados com OCP devem saber que, para realizar o OCP (Princípio Aberto-Fechado), um dos princípios básicos do design orientado a objetos, as classes abstratas são a chave.
Olhando para a classe abstrata e a interface do nível de definição gramatical
No nível gramatical, a linguagem Java fornece diferentes métodos de definição para classe abstrata e interface. A seguir está um exemplo de definição de uma classe abstrata chamada Demo para ilustrar essa diferença.
A maneira de definir a classe abstrata Demo usando a classe abstrata é a seguinte:
classe abstrata Demonstração{
método vazio abstrato1();
método vazio abstrato2();
…
}
A maneira de definir a classe abstrata Demo usando interface é a seguinte:
demonstração de interface{
método vazio1();
método vazio2();
…
}
No método de classe abstrata, Demo pode ter seus próprios membros de dados ou métodos de membros não abstratos. No método de interface, Demo pode ter apenas membros de dados estáticos que não podem ser modificados (ou seja, devem ser finais estáticos, mas dados). os membros geralmente não são definidos na interface) e todos os métodos dos membros são abstratos. De certo modo, interface é uma forma especial de classe abstrata.
Do ponto de vista da programação, tanto a classe abstrata quanto a interface podem ser usadas para implementar a ideia de "design por contrato". No entanto, ainda existem algumas diferenças no uso específico.
Em primeiro lugar, a classe abstrata representa um relacionamento de herança na linguagem Java, e uma classe só pode usar o relacionamento de herança uma vez (porque Java não suporta herança múltipla – nota de transferência). No entanto, uma classe pode implementar múltiplas interfaces. Talvez este seja um compromisso dos projetistas da linguagem Java ao considerar o suporte do Java para herança múltipla.
Em segundo lugar, na definição da classe abstrata, podemos atribuir o comportamento padrão do método. Mas na definição de interface, os métodos não podem ter comportamento padrão. Para contornar essa restrição, devem ser usados delegados, mas isso adicionará alguma complexidade e às vezes causará muitos problemas.
Há outro problema sério em não ser capaz de definir o comportamento padrão em uma classe abstrata: isso pode causar problemas de manutenção. Porque se mais tarde você quiser modificar a interface da classe (geralmente representada por uma classe abstrata ou interface) para se adaptar a novas situações (por exemplo, adicionar novos métodos ou adicionar novos parâmetros a métodos já usados), será muito problemático. pode levar muito tempo (especialmente se houver muitas classes derivadas). Mas se a interface for implementada por meio de uma classe abstrata, talvez você só precise modificar o comportamento padrão definido na classe abstrata.
Da mesma forma, se o comportamento padrão não puder ser definido em uma classe abstrata, a mesma implementação de método aparecerá em todas as classes derivadas da classe abstrata, violando o princípio "uma regra, um lugar", resultando em duplicação de código, o que também é prejudicial para a manutenção futura. Portanto, tenha muito cuidado ao escolher entre classe abstrata e interface.
Olhando para a classe abstrata e a interface do nível do conceito de design
O texto acima discute principalmente a diferença entre classe abstrata e interface do ponto de vista da definição gramatical e da programação. As diferenças nesses níveis são de nível relativamente baixo e não essenciais. Esta seção analisará a diferença entre classe abstrata e interface de outro nível: os conceitos de design refletidos nas duas. O autor acredita que somente analisando a partir deste nível poderemos compreender a essência dos dois conceitos.
Conforme mencionado anteriormente, a classe abstrata incorpora um relacionamento de herança na linguagem Java. Para tornar o relacionamento de herança razoável, deve haver um relacionamento "é um" entre a classe pai e a classe derivada, ou seja, a classe pai e a classe pai. a classe derivada tem o mesmo conceito. Essencialmente, deve ser o mesmo. Este não é o caso das interfaces. O implementador da interface e a definição da interface não precisam ser conceitualmente consistentes, mas apenas implementar o contrato definido pela interface. Para facilitar a compreensão da discussão, um exemplo simples será ilustrado a seguir.
Considere tal exemplo. Suponha que haja um conceito abstrato sobre Porta em nosso domínio de problema. A Porta tem duas ações: abrir e fechar. Neste momento, podemos definir um tipo que representa o conceito abstrato por meio de uma classe abstrata ou definição. os métodos são os seguintes:
Use classe abstrata para definir Porta:
classe abstrata Porta{
vazio abstrato open();
abstrato vazio fechar();
}
Defina a porta usando o método de interface:
porta de interface{
vazio aberto();
void fechar();
}
Outros tipos específicos de Porta podem estender a Porta definida usando o método de classe abstrata ou implementar a Porta definida usando o método de interface. Parece que não há grande diferença entre usar classe abstrata e interface.
Agora é necessário que a porta tenha uma função de alarme. Como devemos projetar a estrutura de classes para este exemplo (neste exemplo, é principalmente para mostrar a diferença nos conceitos de design entre classe abstrata e interface, e outras questões irrelevantes foram simplificadas ou ignoradas)? As possíveis soluções estão listadas abaixo e essas diferentes opções são analisadas a partir do nível de conceito de design.
Solução um:
Basta adicionar um método de alarme à definição de Porta, como segue:
classe abstrata Porta{
vazio abstrato open();
abstrato vazio fechar();
alarme de vazio abstrato();
}
ou
porta de interface{
vazio aberto();
void fechar();
alarme vazio();
}
Então o AlarmDoor com função de alarme é definido da seguinte forma:
classe AlarmDoor estende Porta{
vazio aberto(){…}
vazio fechar(){…}
alarme vazio(){…}
}
ou
classe AlarmDoor implementa Door{
vazio aberto(){…}
vazio fechar(){…}
alarme vazio(){…}
}
Este método viola o ISP (Princípio de Segregação de Interface), um princípio fundamental no design orientado a objetos. Na definição de Porta, o método de comportamento inerente ao próprio conceito de Porta é misturado com o método de comportamento de outro conceito de "alarme". Um problema causado por isso é que os módulos que contam apenas com o conceito de Porta serão alterados devido a alterações no conceito de “alarme” (por exemplo, modificação dos parâmetros do método de alarme), e vice-versa.
Solução dois:
Dado que abrir, fechar e alarme pertencem a dois conceitos diferentes, de acordo com o princípio ISP, devem ser definidos em classes abstratas que representem estes dois conceitos. Os métodos de definição são: ambos os conceitos são definidos usando o método de classe abstrata; ambos os conceitos são definidos usando o método de interface;
Obviamente, como a linguagem Java não suporta herança múltipla, não é viável definir ambos os conceitos usando classes abstratas. Os dois últimos métodos são ambos viáveis, mas a sua escolha reflecte a compreensão da essência do conceito no domínio do problema e se o reflexo da intenção do design é correcto e razoável. Vamos analisar e explicar um por um.
Se ambos os conceitos forem definidos usando o método de interface, então isso reflete dois problemas: 1. Podemos não compreender claramente o domínio do problema. O AlarmDoor é essencialmente uma porta ou um alarme? 2. Se não houver nenhum problema com a nossa compreensão do domínio do problema, por exemplo: através da análise do domínio do problema, descobrimos que o AlarmDoor é conceitualmente consistente com o Door, então não seremos capazes de revelar corretamente a nossa intenção de design ao implementá-lo , porque as definições desses dois conceitos (ambos definidos usando o método de interface) não refletem o significado acima.
Se a nossa compreensão do domínio do problema for: AlarmDoor é conceitualmente essencialmente uma Porta e também tem a função de alarmar. Como devemos projetá-lo e implementá-lo para refletir claramente o nosso significado? Conforme mencionado anteriormente, a classe abstrata representa um relacionamento de herança na linguagem Java, e o relacionamento de herança é essencialmente um relacionamento "é um". Portanto, para o conceito de Porta, devemos usar o método da classe abstrata para defini-la. Além disso, AlarmDoor possui uma função de alarme, o que significa que pode completar o comportamento definido no conceito de alarme, para que o conceito de alarme possa ser definido através da interface. Conforme mostrado abaixo:
classe abstrata Porta{
vazio abstrato open();
abstrato vazio fechar();
}
interfaceAlarme{
alarme vazio();
}
classe Alarme Porta estende Porta implementa Alarme{
vazio aberto(){…}
vazio fechar(){…}
alarme vazio(){…}
}
Este método de implementação pode basicamente refletir claramente nossa compreensão do domínio do problema e revelar corretamente nossas intenções de design. Na verdade, a classe abstrata representa o relacionamento "é um" e a interface representa o relacionamento "como um". É claro que isso se baseia na compreensão do domínio do problema. exemplo: Se AlarmDoor for essencialmente um alarme em conceito e tiver a função de uma Porta, então a definição acima deve ser invertida.
resumo
1.A classe abstrata representa um relacionamento de herança na linguagem Java, e uma classe só pode usar o relacionamento de herança uma vez. No entanto, uma classe pode implementar múltiplas interfaces.
2. Na classe abstrata, você pode ter seus próprios membros de dados e também pode ter métodos de membros não abstratos, mas na interface, você só pode ter membros de dados estáticos que não podem ser modificados (ou seja, eles devem ser estáticos finais, mas na interface os membros dos dados geralmente não são definidos) e todos os métodos dos membros são abstratos.
3. A classe abstrata e a interface refletem diferentes conceitos de design. Na verdade, a classe abstrata representa o relacionamento “é um” e a interface representa o relacionamento “como um”.
4. Classes que implementam classes e interfaces abstratas devem implementar todos os métodos nelas. Classes abstratas podem ter métodos não abstratos. Não pode haver métodos de implementação na interface.
5. As variáveis definidas na interface são public static final por padrão, e seu valor inicial deve ser fornecido, portanto não podem ser redefinidas na classe de implementação, nem seus valores podem ser alterados.
6. Variáveis em classes abstratas são amigáveis por padrão e seus valores podem ser redefinidos em subclasses ou reatribuídos.
7. Os métodos na interface são do tipo público e abstrato por padrão.
para concluir
Classe abstrata e interface são duas maneiras de definir classes abstratas na linguagem Java e são muito semelhantes. No entanto, a sua seleção muitas vezes reflete a compreensão da essência do conceito no domínio do problema e se o reflexo da intenção do projeto é correto e razoável, porque expressam diferentes relações entre conceitos (embora todos possam atingir as funções exigidas). Na verdade, este é um tipo de uso idiomático da linguagem. Espero que os leitores possam entendê-lo com atenção.