Eu sei que isso parece uma pergunta estranha, já que o objetivo de dois ou mais objetos compartilharem a mesma classe é que o comportamento deles é o mesmo, ou seja, seus métodos são idênticos.
No entanto, estou curioso para saber se existem linguagens OOP que permitem redefinir os métodos de objetos da mesma maneira que você pode atribuir valores diferentes para seus campos. O resultado seria objetos construídos a partir da mesma classe que não exibem mais exatamente o mesmo comportamento.
Se não me engano, você pode fazer esse JavaScript? Junto com essa pergunta, pergunto: por que alguém iria querer fazer isso?
object-oriented
programming-languages
Niko Bellic
fonte
fonte
setClickHandler()
método e fazer com que instâncias diferentes da mesma classe façam coisas muito diferentes. Em idiomas que não possuem expressões lambda convenientes, é mais fácil criar uma nova subclasse anônima apenas para um novo manipulador. Tradicionalmente, os métodos de substituição eram considerados a marca registrada de uma nova classe, enquanto a definição dos valores dos atributos não era, mas especialmente com as funções do manipulador, os dois têm efeitos muito semelhantes, então a distinção se torna uma guerra por palavras.Respostas:
Os métodos na maioria dos idiomas OOP (baseados em classe) são corrigidos por tipo.
O JavaScript é baseado em protótipo, não em classe e, portanto, você pode substituir os métodos em uma base por instâncias, porque não há distinção rígida entre "classe" e objeto; na realidade, uma "classe" em JavaScript é um objeto que é como um modelo de como as instâncias devem funcionar.
Qualquer linguagem que permita funções de primeira classe, Scala, Java 8, C # (via delegados) etc, pode agir como se você tivesse substituições de método por instância; você precisaria definir um campo com um tipo de função e substituí-lo em cada instância.
Scala tem outra possibilidade; No Scala, você pode criar singletons de objetos (usando a palavra-chave object em vez da palavra-chave class), para poder estender sua classe e substituir os métodos, resultando em uma nova instância dessa classe base com substituições.
Por que alguém faria isto? Pode haver dezenas de razões. Pode ser que o comportamento precise ser mais definido do que o permitido por várias combinações de campos. Também poderia manter o código dissociado e organizado melhor. No entanto, em geral, acho esses casos mais raros e geralmente há uma solução mais direta usando valores de campo.
fonte
É difícil adivinhar a motivação da sua pergunta e, portanto, algumas respostas possíveis podem ou não atender ao seu interesse real.
Mesmo em algumas linguagens sem protótipo, é possível aproximar esse efeito.
Em Java, por exemplo, uma classe interna anônima é muito próxima do que você está descrevendo - você pode criar e instanciar uma subclasse do original, substituindo apenas o método ou métodos que você deseja. A classe resultante será
instanceof
a classe original, mas não será a mesma classe.Por que você quer fazer isso? Com as expressões lambda do Java 8, acho que muitos dos melhores casos de uso desaparecem. Com versões anteriores do Java, pelo menos, isso pode evitar a proliferação de classes triviais e de uso restrito. Ou seja, quando você tem um grande número de casos de uso relacionados, diferindo apenas de uma maneira funcional minúscula, é possível criá-los quase em movimento (quase), com a diferença de comportamento injetada no momento em que você precisa.
Dito isto, mesmo antes do J8, isso geralmente pode ser refatorado para mudar a diferença para um campo ou três e injetá-las no construtor. Com o J8, é claro, o próprio método pode ser injetado na classe, embora possa haver uma tentação de fazê-lo quando outra refatoração for mais limpa (se não for tão legal).
fonte
Você solicitou qualquer idioma que forneça métodos por instância. Já existe uma resposta para Javascript, então vamos ver como isso é feito no Common Lisp, onde você pode usar os especialistas em EQL:
Por quê?
Os especialistas em EQL são úteis quando o argumento sujeito a despacho deve ter um tipo para o qual
eql
faz sentido: um número, um símbolo etc. Em geral, você não precisa dele e simplesmente precisa definir quantas subclasses necessário pelo seu problema. Mas, às vezes, você só precisa despachar de acordo com um parâmetro que é, por exemplo, um símbolo: umacase
expressão seria limitada aos casos conhecidos na função de despacho, enquanto os métodos podem ser adicionados e removidos a qualquer momento.Além disso, a especialização em instâncias é útil para fins de depuração, quando você deseja inspecionar temporariamente o que acontece com um objeto específico em seu aplicativo em execução.
fonte
Você também pode fazer isso no Ruby usando objetos singleton:
Produz:
Quanto aos usos, é assim que Ruby efetua os métodos de classe e módulo. Por exemplo:
Na verdade, está definindo um método singleton
hello
noClass
objetoSomeClass
.fonte
extend
na verdade, apenas cria a classe singleton para o objeto e depois importa o módulo para a classe singleton.Você pode pensar em métodos por instância como permitindo montar sua própria classe em tempo de execução. Isso pode eliminar muito código de cola, código que não tem outro objetivo senão reunir duas classes para conversar entre si. Os mixins são uma solução um pouco mais estruturada para os mesmos tipos de problemas.
Você está sofrendo um pouco com o paradoxo do blub , basicamente é difícil ver o valor de um recurso de linguagem até que você o use em um programa real. Portanto, procure oportunidades nas quais você acha que pode funcionar, tente e veja o que acontece.
Procure no seu código grupos de classes que diferem apenas por um método. Procure por classes cujo único objetivo é combinar duas outras classes em combinações diferentes. Procure métodos que não fazem nada além de passar uma chamada para outro objeto. Procure por classes instanciadas usando padrões criacionais complexos . Todos esses são candidatos em potencial a serem substituídos por métodos por instância.
fonte
Outras respostas mostraram como esse é um recurso comum das linguagens dinâmicas orientadas a objetos e como ele pode ser emulado trivialmente em uma linguagem estática que possui objetos de função de primeira classe (por exemplo, delegados em c #, objetos que substituem operador () em c ++) . Em linguagens estáticas que carecem dessa função, é mais difícil, mas ainda pode ser alcançado usando uma combinação do padrão Strategy e um método que simplesmente delega sua implementação à estratégia. Isso é efetivamente o mesmo que você faria em c # com delegados, mas a sintaxe é um pouco mais confusa.
fonte
Você pode fazer algo assim em C # e na maioria dos outros idiomas semelhantes.
fonte
Conceitualmente, mesmo que em uma linguagem como Java todas as instâncias de uma classe devam ter os mesmos métodos, é possível fazer parecer que não, adicionando uma camada extra de indireção, possivelmente em combinação com classes aninhadas.
Por exemplo, se uma classe
Foo
pode definir uma classe aninhada abstrata estáticaQuackerBase
que contém um métodoquack(Foo)
, bem como várias outras classes aninhadas estáticas derivadasQuackerBase
, cada uma com sua própria definição dequack(Foo)
, então se a classe externa tiver um campoquacker
do tipoQuackerBase
, poderá defina esse campo para identificar uma instância (possivelmente singleton) de qualquer uma de suas classes aninhadas. Depois disso, a chamadaquacker.quack(this)
executará oquack
método da classe cuja instância foi atribuída a esse campo.Como esse é um padrão bastante comum, o Java inclui mecanismos para declarar automaticamente os tipos apropriados. Esses mecanismos não estão realmente fazendo algo que não poderia ser feito simplesmente usando métodos virtuais e classes estáticas aninhadas opcionalmente, mas reduzem bastante a quantidade de clichê necessária para produzir uma classe cujo único objetivo é executar um único método em nome de outra classe.
fonte
Eu acredito que é a definição de uma linguagem "dinâmica" como ruby, groovy e Javascript (e muitos outros). Dinâmico refere-se (pelo menos em parte) à capacidade de redefinir dinamicamente como uma instância de classe pode se comportar em tempo real.
Geralmente, não é uma boa prática OO, mas para muitos programadores de linguagem dinâmica os princípios OO não são sua principal prioridade.
Isso simplifica algumas operações complicadas, como o Monkey-Patching, onde você pode ajustar uma instância de classe para permitir que você interaja com uma biblioteca fechada de uma maneira que eles não previam.
fonte
Não estou dizendo que é uma coisa boa a se fazer, mas isso é trivialmente possível em Python. Não consigo pensar em um bom caso de uso, mas tenho certeza de que eles existem.
fonte