Em este vídeo por Rich Hickey , o criador Clojure, ele aconselha a usar o mapa para representar dados em vez de usar uma classe para representá-lo, como foi feito em Java. Não entendo como pode ser melhor, pois como o usuário da API pode saber quais são as chaves de entrada se elas são simplesmente representadas como mapas.
Exemplo :
PersonAPI {
Person addPerson(Person obj);
Map<String, Object> addPerson(Map<String, Object> personMap);
}
Na segunda função, como o usuário da API pode saber quais são as entradas para criar uma pessoa?
Respostas:
Resumo executivo (TM)
Você recebe algumas coisas.
Há uma desvantagem fatal.
O problema é que você pode obter introspecção usando, hum, introspecção. Isto é o que geralmente acontece:
Em outras palavras, se você nunca precisar interagir com o FP, não precisará seguir o conselho de Rich Hickey.
Por último, mas não menos importante (nem o mais bonito), embora usar
String
como chave de propriedade faça o sentido mais direto, você não precisa usarString
s. Muitos sistemas legados, incluindo o Android ™, usam IDs inteiros extensivamente em toda a estrutura para se referir a classes, propriedades, recursos etc.Android é uma marca comercial da Google Inc.
Você também pode fazer os dois mundos felizes.
Para o mundo Java, implemente os getters e setters como de costume.
Para o mundo do FP, implemente o
Object getPropertyByName(String name)
void setPropertyByName(String name, Object value) throws IllegalPropertyChangeException
List<String> getPropertyNames()
Class<?> getPropertyValueClass(String name)
Dentro dessas funções, sim, código feio, mas existem plugins IDE que o preencherão, usando ... uh, um plug-in inteligente que lê seu código.
O lado Java das coisas terá o mesmo desempenho de sempre. Eles nunca usarão essa parte feia do código. Você pode até querer escondê-lo do Javadoc.
O lado FP do mundo pode escrever o código "leet" que eles querem, e geralmente não gritam com você sobre o código ser lento.
Em geral, o uso de um mapa (bolsa de propriedades) no lugar do objeto é comum no desenvolvimento de software. Não é exclusivo da programação funcional ou de qualquer tipo específico de linguagem. Pode não ser uma abordagem idiomática para qualquer idioma, mas há situações que exigem isso.
Em particular, serialização / desserialização geralmente requer uma técnica semelhante.
Apenas algumas idéias gerais sobre "mapa como objeto".
fonte
commonplace
parece um pouco forte para mim. Quero dizer, é usado como você descreve, mas também é uma daquelas coisas notoriamente desleixadas / frágeis (como matrizes de bytes ou ponteiros), que as bibliotecas tentam esconder.É uma excelente conversa de alguém que realmente sabe do que está falando. Eu recomendo que os leitores assistam a coisa toda. São apenas 36 minutos.
Um de seus principais pontos é que a simplicidade abre oportunidades para mudanças mais tarde. A escolha de uma classe para representar a
Person
fornece o benefício imediato da criação de uma API estaticamente verificável, como você apontou, mas que vem com o custo de limitar oportunidades ou aumentar os custos de mudança e reutilização posteriormente.Seu argumento é que o uso da classe pode ser uma escolha razoável, mas deve ser uma escolha consciente que tenha plena consciência de seu custo, e os programadores tradicionalmente fazem um trabalho muito ruim ao perceber esses custos, muito menos levá-los em consideração. Essa escolha deve ser reavaliada à medida que seus requisitos aumentam.
A seguir, algumas alterações de código (uma ou duas mencionadas na conversa) que são potencialmente mais simples usando uma lista de mapas em comparação com o uso de uma lista de
Person
objetos:Map
das primitivas em um formato transmissível é altamente reutilizável e pode até ser fornecida em uma biblioteca.Person
É provável que um objeto precise de código personalizado para realizar o mesmo trabalho).Resolvemos esses tipos de problemas o tempo todo e temos padrões e ferramentas para eles, mas raramente paramos para pensar se escolher uma representação de dados mais simples e flexível no começo facilitaria nosso trabalho.
fonte
Choosing a class to represent a Person provides the immediate benefit of creating a statically-verifiable API... but that comes with the cost of limiting opportunities or increasing costs for change and reuse later on.
Errado e incrivelmente falso. Isso melhora a sua oportunidade de alterar posteriormente, porque quando você faz uma alteração de última hora, o compilador encontrará e apontará automaticamente todos os lugares que precisam ser atualizados para acelerar toda a sua base de código. É no código dinâmico, onde você não pode fazer isso, que realmente se acopla às escolhas anteriores!Se os dados tiverem pouco ou nenhum comportamento, com conteúdo flexível que provavelmente será alterado, use um Mapa. O IMO, um "javabean" típico ou "Objeto de Dados" que consiste em um Modelo de Domínio Anêmico com N campos, N setters e N getters, é uma perda de tempo. Não tente impressionar os outros com sua estrutura glorificada, envolvendo-a em uma classe smancia sofisticada. Seja honesto, esclareça suas intenções e use um mapa. (Ou, se fizer sentido para o seu domínio, um objeto JSON ou XML)
Se os dados tiverem um comportamento real significativo, também conhecido como métodos ( Tell, Don't Ask ), use uma classe. E dê um tapinha nas costas por usar programação real orientada a objetos :-).
Se os dados tiverem muitos comportamentos essenciais de validação e campos obrigatórios, use uma classe.
Se os dados têm uma quantidade moderada de comportamento de validação, isso é limítrofe.
Se os dados disparam eventos de mudança de propriedade, isso é realmente mais fácil e muito menos tedioso com um Mapa. Basta escrever uma pequena subclasse.
Uma desvantagem principal do uso de um mapa é que o usuário deve converter os valores em Strings, ints, Foos, etc. Se isso for altamente irritante e propenso a erros, considere uma classe. Ou considere uma classe auxiliar que agrupe o mapa com os getters relevantes.
fonte
A API para a
map
tem dois níveis.A API pode ser descrita no mapa por convenção. Por exemplo, o par
:api api-validate
pode ser colocado no mapa ou:api-foo validate-foo
pode ser a convenção. O mapa pode até armazenarapi api-documentation-link
.O uso de convenções permite que o programador crie uma linguagem específica de domínio que padronize o acesso entre os "tipos" implementados como mapas. O uso
(keys map)
permite determinar propriedades no tempo de execução.Não há nada de mágico nos mapas e não há nada de mágico nos objetos. É tudo expedição.
fonte