Congratulazioni! Hai appena circumnavigato il globo del linguaggio / tipo di sistema di programmazione, arrivando dall'altra parte del mondo da dove sei partito. Sei appena atterrato al confine di un linguaggio dinamico / terra di oggetti basata su prototipi!
Molti linguaggi dinamici (ad esempio JavaScript, PHP, Python) consentono di estendere o modificare le proprietà degli oggetti in fase di esecuzione.
La forma estrema di questo è un linguaggio basato su prototipo come Self o JavaScript. Non hanno lezioni, a rigor di termini. Puoi fare cose che sembrano una programmazione basata su classi, orientata agli oggetti con ereditarietà, ma le regole sono molto più rilassate rispetto a linguaggi più definiti e basati su classi come Java e C #.
Langauges come PHP e Python vivono nella terra di mezzo. Hanno sistemi regolari, basati su classi idiomatiche. Ma gli attributi degli oggetti possono essere aggiunti, modificati o eliminati in fase di esecuzione - anche se con alcune restrizioni (come "ad eccezione dei tipi predefiniti") che non trovi in JavaScript.
Il grande compromesso per questo dinamismo è la prestazione. Dimentica quanto fortemente o debolmente è scritta la lingua o quanto bene può essere compilata fino al codice macchina. Gli oggetti dinamici devono essere rappresentati come mappe / dizionari flessibili, piuttosto che semplici strutture. Ciò aggiunge sovraccarico ad ogni accesso agli oggetti. Alcuni programmi fanno di tutto per ridurre questo sovraccarico (ad es. Con l'assegnazione fantasma di kwarg e le classi basate su slot in Python), ma l'overhead aggiuntivo di solito è solo alla pari per il corso e il prezzo dell'ammissione.
Tornando al tuo design, stai innestando la possibilità di avere proprietà dinamiche su un sottoinsieme delle tue classi. A Product
può avere attributi variabili; presumibilmente un Invoice
o un Order
sarebbe e non potrebbe. Non è un brutto modo di andare. Ti dà la flessibilità di avere variazioni dove ne hai bisogno, pur rimanendo in un linguaggio rigoroso e disciplinato e un sistema di tipi. Sul lato negativo, sei responsabile della gestione di quelle proprietà flessibili e probabilmente dovrai farlo attraverso meccanismi che sembrano leggermente diversi dagli altri attributi nativi. p.prop('tensile_strength')
piuttosto che p.tensile_strength
, per esempio, e p.set_prop('tensile_strength', 104.4)
piuttosto chep.tensile_strength = 104.4
. Ma ho lavorato e creato molti programmi in Pascal, Ada, C, Java e persino in linguaggi dinamici che utilizzavano esattamente tale accesso getter-setter per tipi di attributi non standard; l'approccio è chiaramente praticabile.
A proposito, questa tensione tra tipi statici e un mondo molto vario è estremamente comune. Un problema analogo si riscontra spesso durante la progettazione dello schema del database, in particolare per gli archivi di dati relazionali e pre-relazionali. A volte viene affrontato creando "super-righe" che contengono abbastanza flessibilità per contenere o definire l'unione di tutte le varianti immaginate, quindi riempire tutti i dati che arrivano in quei campi. Il WordPress wp_posts
tavolo , per esempio, ha campi come comment_count
, ping_status
, post_parent
e post_date_gmt
che sono interessanti solo in alcune circostanze, e che in pratica vanno spesso vuota. Un altro approccio è un tavolo molto normalewp_options
, molto simile, proprio come il tuoProperty
classe. Sebbene richieda una gestione più esplicita, gli elementi in essa contenuti sono raramente vuoti. I database orientati agli oggetti e ai documenti (ad es. MongoDB) spesso hanno un tempo più facile a gestire le opzioni di modifica, perché possono creare e impostare gli attributi praticamente a piacimento.