Esiste un modello per descrivere una classe che simboleggia un'istanza di un'istanza di un'altra classe?

2

Attualmente sto lavorando a un progetto che genera video da modelli (un modello è una raccolta di file e risorse JSON).

Sembra naturale avere una classe Template che contenga tutte le informazioni su come questo modello specifico è strutturato (ad esempio quali parti sono personalizzabili, quali risorse sono richieste ecc ...).

Il problema su cui sono stato appeso è come modellare un lavoro. Un lavoro richiede un determinato Template , consente l'assegnazione di valori ai campi personalizzabili e il rendering di un video utilizzando questi valori. Per me, ha senso che un Job sia un'istanza di un'istanza di Template .

Una soluzione che sto immaginando è qualcosa del genere (in pseudo-Typescript):

class Template {
    // elements in groups can be subclasses of the generic TemplateField - I'd like to preserve that and their grouping in the DynamicallyCreatedTemplateClass that is generated below
    templateFields : Group<TemplateField>[];

    constructor( sourcePath : string) {
        // build shape of templateFields from a file
    }

    // This should return a constructor for a dynamically created class that inherits from Template as well as a Job mixin but already has a concrete structure in this.templateFields
    // in general, the resulting class should resemble the Template instance this is called on (i.e. properties that have values on the instance should have the same values in every instance of the generated class)
    getInstanceClass() : () => DynamicallyCreatedTemplateClass { /* ??? */ }
}

const someTemplate = new Template('/path/to/some/file.json');

const someJob = new someTemplate.getInstanceClass();

someJob.templateFields[0].get(0).value = 'something';
if(
    someJob.templateFields[0].get(0).type == someTemplate.templateFields[0].get(0).type &&
    typeof someTemplate.templateFields[0].get(0).value === 'undefined'
)
        console.log('success!');

Esiste uno schema per descrivere questa relazione o sto sbagliando tutto questo?

    
posta Jan Hettenkofer 06.07.2018 - 22:28
fonte

3 risposte

0

Bene, ecco i miei pensieri dopo aver ascoltato i tuoi suggerimenti:

Prima di tutto, un Template dovrebbe essere solo una classe di dati che legge un file di configurazione e quindi esiste in quello stato senza fare molto.

Ci sono due modi in cui un modello può essere interagito con:

1) la sua configurazione può essere cambiata (cioè campi Template aggiunti / rimossi, beni modificati, anteprime generate ecc ...)

2) i suoi campi possono essere riempiti con valori e possono essere resi

Avevo la prima mescolata con i dati del modello e la seconda è stata modellata come un lavoro.

Quindi, tenendo conto di ciò, ho trovato questo:

// this is a necessity for mixins in TypeScript
type Constructor<T> = new(...args: any[]) => T;

// the "pure data" template class
class Template {
    templateFieldGroups : TemplateFieldGroup[];
    // other properties

    constructor() {
        // load from disk
    }
}

// The mixin to add Job-specific functionality (saving TemplateField values and rendering)
function JobMixin<T extends Constructor<Template>>(Base : T) {
    return class extends Base {
        constructor(...args: any[]) {
            super(...args);
        }

        render(){}
        saveValuesToDB(){}
        loadValuesFromDB(){}
    }
}

// The mixin to add management functionality
function TemplateManagerMixin<T extends Constructor<Template>>(Base : T) {
    return class extends Base {
        constructor(...args: any[]) {
            super(...args);
        }

        createPreviews(){}
    }
}

// The class that will be used to configure the templates
class TemplateManager extends TemplateManagerMixin(Template) {
}

// The class that will be used to handle specific template instances and render them
class Job extends JobMixin(Template) {
}

Non so se questo è davvero il modo migliore per farlo, ma sembra essere abbastanza intuitivo dal punto di vista dell'usabilità per me.

Grazie ancora a kamikaze e Thomas Junk per il tuo contributo.

    
risposta data 08.07.2018 - 14:05
fonte
3

La domanda è: cosa vuoi ottenere usando questo design. Se ciò che intendi fare ha un senso può anche dipendere dal fatto che è il modo comune per farlo nella lingua che hai scelto.

Per me la tua spiegazione mi sembra che il tuo lavoro sia ereditato dal tuo Template.

Il tuo codice sembra che il tuo modello sia una fabbrica di lavoro.

Quest'ultimo ha più senso per me. Lo scopo dell'ereditarietà è quello di ottenere il polimorfismo di runtime. Un modello non è un lavoro e viceversa.

Rendere il tuo modello una fabbrica di lavoro ha perfettamente senso. Quello che vorrei raccomandare è che il tuo lavoro prenda un riferimento di modello nel suo costruttore per creare un'aggregazione (questo è anche chiamato iniezione di dipendenza).

In C ++ vorrei dichiarare friend class Template e rendere privato il costruttore di Job in modo che solo il tuo Job factory (ovvero la classe Template) possa creare lavori.

In Java renderei protetto il costruttore di Job e inserirli in uno spazio dei nomi comune.

    
risposta data 07.07.2018 - 02:34
fonte
0

Da quello che vedo qui, avrebbe senso avere i seguenti componenti:

  • Modello: contiene le informazioni necessarie per il rendering. Limita la modifica di alcune delle sue parti. Rende stesso

  • Template Builder - che configura il modello con le informazioni necessarie.

Il flusso modellato sarebbe qualcosa del tipo:

template = new TemplateBuilder(config).build();
template.render()

Nessun "lavoro" richiesto.

Il tuo "modello" è qualcosa come un factory e il tuo job esegue qualche configurazione ed esegue il "rendering", che dal mio punto di vista non dovrebbe - perché non è una sua responsabilità.

    
risposta data 07.07.2018 - 08:18
fonte