Parabéns! Você acabou de circunavegar o globo do sistema de linguagem / tipo de programação, chegando ao outro lado do mundo de onde partiu. Você acabou de desembarcar na fronteira da linguagem dinâmica / do objeto baseado em protótipo!
Muitas linguagens dinâmicas (por exemplo, JavaScript, PHP, Python) permitem estender ou alterar as propriedades do objeto em tempo de execução.
A forma extrema disso é uma linguagem baseada em protótipo como Self ou JavaScript. Eles não têm aulas, estritamente falando. Você pode fazer coisas que se parecem com programação baseada em classe e orientada a objetos com herança, mas as regras são bastante flexíveis em comparação com linguagens baseadas em classes mais definidas, como Java e C #.
Idiomas como PHP e Python vivem no meio do caminho. Eles têm sistemas regulares baseados em classe idiomáticos. Porém, os atributos do objeto podem ser adicionados, alterados ou excluídos no tempo de execução - embora com algumas restrições (como "exceto tipos internos") que você não encontra no JavaScript.
A grande desvantagem desse dinamismo é o desempenho. Esqueça o quão forte ou fracamente digitada é a linguagem ou quão bem ela pode ser compilada no código da máquina. Objetos dinâmicos devem ser representados como mapas / dicionários flexíveis, em vez de estruturas simples. Isso adiciona sobrecarga a todos os acessos a objetos. Alguns programas envidam grandes esforços para reduzir essa sobrecarga (por exemplo, com atribuição de phantom kwarg e classes baseadas em slot no Python), mas a sobrecarga extra geralmente é apenas par para o curso e o preço da entrada.
Voltando ao seu design, você está enxertando a capacidade de ter propriedades dinâmicas em um subconjunto de suas classes. A Product
pode ter atributos variáveis; presumivelmente um Invoice
ou um Order
faria e não poderia. Não é um mau caminho a percorrer. Ele oferece a flexibilidade de variar onde você precisar, enquanto permanece em um sistema de idioma e tipo estrito e disciplinado. No lado negativo, você é responsável por gerenciar essas propriedades flexíveis e provavelmente precisará fazê-lo por meio de mecanismos que parecem um pouco diferentes dos atributos mais nativos. p.prop('tensile_strength')
em vez de p.tensile_strength
, por exemplo, e em p.set_prop('tensile_strength', 104.4)
vez dep.tensile_strength = 104.4
. Mas trabalhei e construí muitos programas em Pascal, Ada, C, Java e até mesmo linguagens dinâmicas que usavam exatamente esse acesso getter-setter para tipos de atributos não padrão; a abordagem é claramente viável.
A propósito, essa tensão entre tipos estáticos e um mundo altamente variado é extremamente comum. Um problema análogo é frequentemente visto ao projetar o esquema do banco de dados, especialmente para armazenamentos de dados relacionais e pré-relacionais. Às vezes, isso é resolvido através da criação de "super-linhas" que contêm flexibilidade suficiente para conter ou definir a união de todas as variações imaginadas e, em seguida, o preenchimento de todos os dados que aparecem nesses campos. O WordPress wp_posts
mesa , por exemplo, tem campos como comment_count
, ping_status
, post_parent
e post_date_gmt
que só são interessantes em algumas circunstâncias, e que, na prática, muitas vezes ficar em branco. Outra abordagem é uma tabela normalizada muito sobressalente, wp_options
semelhante à suaProperty
classe. Embora exija gerenciamento mais explícito, os itens raramente ficam em branco. Os bancos de dados orientados a objetos e de documentos (por exemplo, MongoDB) costumam ter mais facilidade para lidar com as opções de alteração, porque eles podem criar e definir atributos praticamente à vontade.