Estou tentando entender como o polimorfismo é usado em um projeto da vida real, mas só consigo encontrar o exemplo clássico (ou algo semelhante) de ter uma Animal
classe pai com um método speak()
e muitas classes filho que substituem esse método e agora você pode chamar o método speak()
em qualquer um dos objetos filhos, por exemplo:
Animal animal;
animal = dog;
animal.speak();
animal = cat;
animal.speak();
object-oriented
data-structures
polymorphism
Christopher
fonte
fonte
if(x is SomeType) DoSomething()
frequentemente, pode valer a pena usar polimorfismo. Para mim, o polimorfismo é uma decisão semelhante a quando fazer um método separado. Se descobri que repeti o código algumas vezes, costumo refatorá-lo em um método e, se achar que estou criandoif object is this type do this
código com frequência, talvez seja vale refatorar e adicionar uma interface ou classe.Respostas:
Stream é um ótimo exemplo de polimorfismo.
Stream representa uma "sequência de bytes que pode ser lida ou gravada". Mas essa sequência pode vir de arquivo, memória ou muitos tipos de conexões de rede. Ou pode servir como decorador, que envolve o fluxo existente e transforma os bytes de alguma forma, como criptografia ou compactação.
Dessa forma, o cliente que usa o Stream não precisa se preocupar com a origem dos bytes. Só que eles podem ser lidos em sequência.
Alguns diriam que
Stream
é um exemplo errado de polimorfismo, porque define muitos "recursos" que seus implementadores não suportam, como o fluxo de rede que permite apenas leitura ou gravação, mas não os dois ao mesmo tempo. Ou falta de busca. Mas isso é apenas uma questão de complexidade, poisStream
pode ser subdividido em várias partes que podem ser implementadas independentemente.fonte
Stream
são o meu exemplo de polimorfismo favorito de todos os tempos. Nem sequer tento ensinar às pessoas o modelo defeituoso de 'animal, mamífero, cachorro',Stream
mas fazemos um trabalho melhor.Um exemplo típico relacionado a jogos seria uma classe base
Entity
, fornecendo membros comuns comodraw()
ouupdate()
.Para um exemplo orientado a dados mais puro, poderia haver uma classe base
Serializable
fornecendo umsaveToStream()
eloadFromStream()
.fonte
Existem diferentes tipos de polimorfismo, o de interesse é geralmente polimorfismo em tempo de execução / despacho dinâmico.
Uma descrição de alto nível do polimorfismo de tempo de execução é que uma chamada de método faz coisas diferentes, dependendo do tipo de tempo de execução de seus argumentos: o próprio objeto é responsável por resolver uma chamada de método. Isso permite uma enorme quantidade de flexibilidade.
Uma das maneiras mais comuns de usar essa flexibilidade é a injeção de dependência , por exemplo, para que eu possa alternar entre implementações diferentes ou injetar objetos simulados para teste. Se eu souber com antecedência que haverá apenas um número limitado de opções possíveis, eu poderia tentar codificá-las com condicionais, por exemplo:
Isso dificulta o código. A alternativa é introduzir uma interface para essa operação foo e escrever uma implementação normal e uma implementação simulada dessa interface e "injetar" na implementação desejada em tempo de execução. "Injeção de dependência" é um termo complicado para "transmitir o objeto correto como argumento".
Como exemplo do mundo real, atualmente estou trabalhando em um tipo de problema de aprendizado de máquina. Eu tenho um algoritmo que requer um modelo de previsão. Mas quero experimentar diferentes algoritmos de aprendizado de máquina. Então eu defini uma interface. O que eu preciso do meu modelo de previsão? Dada uma amostra de entrada, a previsão e seus erros:
Meu algoritmo usa uma função de fábrica que treina um modelo:
Agora tenho várias implementações da interface do modelo e posso compará-las umas com as outras. Uma dessas implementações, na verdade, pega dois outros modelos e os combina em um modelo aprimorado. Então, graças a esta interface:
Um caso de uso clássico de polimorfismo está nas GUIs. Em uma estrutura de GUI como Java AWT / Swing /…, existem componentes diferentes . A interface do componente / classe base descreve ações como pintar a própria tela ou reagir a cliques do mouse. Muitos componentes são contêineres que gerenciam subcomponentes. Como esse recipiente pode se desenhar?
Aqui, o contêiner não precisa saber sobre os tipos exatos dos subcomponentes com antecedência - desde que estejam em conformidade com a
Component
interface que o contêiner pode simplesmente chamar depaint()
método polimórfico . Isso me dá a liberdade de estender a hierarquia de classes AWT com novos componentes arbitrários.Existem muitos problemas recorrentes ao longo do desenvolvimento de software que podem ser resolvidos aplicando o polimorfismo como uma técnica. Esses pares problema-solução recorrentes são chamados de padrões de design e alguns deles são coletados no livro de mesmo nome. Nos termos desse livro, meu modelo de aprendizado de máquina injetado seria uma estratégia que eu uso para “definir uma família de algoritmos, encapsular cada um e torná-los intercambiáveis”. O exemplo Java-AWT em que um componente pode conter subcomponentes é um exemplo de composto .
Mas nem todo projeto precisa usar polimorfismo (além de permitir a injeção de dependência para testes de unidade, que é realmente um bom caso de uso). Caso contrário, a maioria dos problemas é muito estática. Como conseqüência, classes e métodos geralmente não são usados para polimorfismo, mas simplesmente como espaços de nomes convenientes e para o método bonito chamar sintaxe. Por exemplo, muitos desenvolvedores preferem chamadas de método como
account.getBalance()
sobre uma chamada de função amplamente equivalenteAccount_getBalance(account)
. Essa é uma abordagem perfeitamente correta, mas muitas chamadas de "método" não têm nada a ver com polimorfismo.fonte
Você vê muita herança e polimorfismo na maioria dos kits de ferramentas da interface do usuário.
Por exemplo, no kit de ferramentas da interface do usuário JavaFX,
Button
herda daButtonBase
qual herda daLabeled
qual herda daControl
qual herda daRegion
qual herda daParent
qual herda daNode
qual herdaObject
. Muitas camadas substituem alguns métodos dos anteriores.Quando você deseja que esse botão apareça na tela, adicione-o a a
Pane
, que pode aceitar qualquer coisa herdadaNode
quando criança. Mas como um Painel sabe o que fazer com um Botão quando o vê apenas como um objeto Nó genérico? Esse objeto pode ser qualquer coisa. O painel pode fazer isso porque o Button redefine os métodos do Node com qualquer lógica específica do botão. O painel chama os métodos definidos no Node e deixa o restante para o próprio objeto. Este é um exemplo perfeito de polimorfismo aplicado.Os kits de ferramentas da interface do usuário têm um significado muito alto no mundo real, tornando-os úteis para ensinar por razões acadêmicas e práticas.
No entanto, os kits de ferramentas da interface do usuário também têm uma desvantagem significativa: eles tendem a ser enormes . Quando um engenheiro de software neófito tenta entender o funcionamento interno de uma estrutura de interface do usuário comum, geralmente encontra mais de cem classes , a maioria delas servindo a propósitos muito esotéricos. "O que diabos é isso
ReadOnlyJavaBeanLongPropertyBuilder
? É importante? Eu tenho que entender para que serve?" Iniciantes podem facilmente se perder nessa toca de coelho. Portanto, eles podem fugir aterrorizados ou permanecer na superfície onde aprendem a sintaxe e tentam não pensar muito sobre o que realmente está acontecendo sob o capô.fonte
Embora já existam bons exemplos aqui, outro é substituir animais por dispositivos:
Device
pode serpowerOn()
,powerOff()
,setSleep()
e latagetSerialNumber()
.SensorDevice
pode fazer tudo isso, e fornecer funções polimórficas, comogetMeasuredDimension()
,getMeasure()
,alertAt(threashhold)
eautoTest()
.getMeasure()
não será implementado da mesma maneira para um sensor de temperatura, um detector de luz, um detector de som ou um sensor volumétrico. E, é claro, cada um desses sensores mais especializados pode ter algumas funções adicionais disponíveis.fonte
A apresentação é um aplicativo muito comum, talvez o mais comum seja ToString (). Que é basicamente Animal.Speak (): você diz para um objeto se manifestar.
De um modo mais geral, você diz a um objeto para "fazer as coisas". Pense em Salvar, Carregar, Inicializar, Dispor, ProcessData, GetStatus.
fonte
Meu primeiro uso prático do polimorfismo foi uma implementação do Heap em java.
Eu tinha classe base com implementação de métodos insert, removeTop onde a diferença entre max e min Heap seria apenas como o método comparar funciona.
Então, quando eu queria ter MaxHeap e MinHeap, eu poderia apenas usar herança.
fonte
Aqui está um cenário da vida real para o polimorfismo da tabela de aplicativos da web / banco de dados :
Uso o Ruby on Rails para desenvolver aplicativos da Web, e uma coisa que muitos dos meus projetos têm em comum é a capacidade de fazer upload de arquivos (fotos, PDFs etc.). Por exemplo, um
User
pode ter várias fotos de perfil e umProduct
também pode ter muitas imagens de produtos. Ambos têm o comportamento de carregar e armazenar imagens, além de redimensionar, gerar miniaturas etc. Para permanecer seco e compartilhar o comportamentoPicture
, queremos tornarPicture
polimórficos para que possam pertencer a ambosUser
eProduct
.No Rails, eu projetava meus modelos da seguinte forma:
e uma migração de banco de dados para criar a
pictures
tabela:As colunas
imageable_id
eimageable_type
são usadas internamente pelo Rails. Basicamente,imageable_type
contém o nome da classe ("User"
,"Product"
, etc.), eimageable_id
é o id do registro associado. Então,imageable_type = "User"
eimageable_id = 1
seria o registro nausers
tabela comid = 1
.Isso nos permite fazer coisas como
user.pictures
acessar as fotos do usuário eproduct.pictures
obter as fotos de um produto. Então, todo o comportamento relacionado à imagem é encapsulado naPhoto
classe (e não uma classe separada para cada modelo que precisa de fotos), para que as coisas sejam mantidas SECA.Mais leitura: Associações polimórficas do Rails .
fonte
Existem muitos algoritmos de classificação disponíveis, como classificação de bolhas, classificação de inserção, classificação rápida, classificação de heap, etc.
O cliente fornecido com a interface de classificação preocupa-se apenas em fornecer a matriz como uma entrada e, em seguida, recebe a matriz classificada. Durante o tempo de execução, dependendo de certos fatores, a implementação apropriada da classificação pode ser usada. Este é um exemplo do mundo real de onde o polimorfismo é usado.
O que eu descrevi acima é um exemplo de polimorfismo em tempo de execução, enquanto a sobrecarga de método é um exemplo de polimorfismo em tempo de compilação, quando mais completas, dependendo dos tipos de parâmetros i / pe / o / p e o número de parâmetros vincula o chamador ao método correto no próprio tempo de conformidade.
Espero que isso esclareça.
fonte