Domanda

Alcuni codici possono dire più di mille parole:

/**
 * Represents an amount of a resource
 * @param {number} amount
 * @param {string} type
 */
function Resource(amount, type) 
{
    var nAmount = amount;
    var sType = type;

    if (amount < 0) 
    {
        throw new IllegalArgumentException("amount has to be positive");
    }

    /**
     * @method Resource
     * @return {number} amount of the resource
     */
    this.getAmount = function() 
    {
        return nAmount;
    };

    /**
     * @method Resource
     * @return {string} resource type
     */
    this.getType = function() 
    {
        return sType;
    };
}

/**
 * Addition of two resources produces a new resource with the sum amount
 * the new object uses the old one as prototype
 * @param {Resource} resource
 * @return {Resource} new Resource object
 */
Resource.prototype.plus = function(resource) 
{
    if (!(resource instanceof Resource && this.getType() == resource.getType())) 
    {
        throw new IllegalArgumentException("resources don't match.");
    }

    var newRes = Object.create(this); // create a new object based on the current one
    // execute the Resource constructor on it
    Resource.call(newRes, this.getAmount() + resource.getAmount(), this.getType());
    return newRes;
};

Gli oggetti risorsa sono ValueObject considerati immutabili.Restituiscono un nuovo oggetto in un'operazione di addizione.Ora invece di chiamare semplicemente "new Resource(args)" per creare il nuovo oggetto da restituire, ne ho creato uno nuovo basato sul vecchio oggetto.Ciò consente anche l'ereditarietà.

Poiché sto iniziando a usarlo su tutti i miei ValueObject (nel caso in cui volessi ereditare da loro in futuro), ho iniziato a pensarci un po' di più.

JavaScript non consente oggetti immutabili.Tuttavia, gli oggetti sono vulnerabili alla sovrascrittura diretta del metodo o alla chiamata al loro costruttore.Tutto quello che posso fare è decidere che queste sono cattive abitudini.Sfortunatamente il "freeze" di ECMAScript5 non è ancora qui, sebbene il mio pattern sia compatibile con esso.

Ora che ho questo "cattivo stile" di chiamare il costruttore su un oggetto immutabile insieme a questa duplicazione del codice, sto pensando di creare una nuova funzione per incapsulare questa procedura:

Object.recreate = function(proto, constructor, args) 
{
    var obj = Object.create(proto);
    constructor.apply(obj, args);
    return obj;
};

E quindi:

Resource.prototype.plus = function(resource) 
{
    // if ... {throw ...}
    return Object.recreate(this, Resource, 
            [this.getAmount() + resource.getAmount(), this.getType()]);
};

Forse qualcuno ha un'idea migliore per il nome di questa funzione.'Ricreare' è stato il mio primo pensiero.Cosa ne pensi di questo modello?È un'astrazione eccessiva?Dovrei salvarlo per le classi da cui sono sicuro che erediterò?Mi sono perso qualcosa di importante?

Modificare:Vedo che ho dimenticato di menzionare qualcosa di importante che al momento non si riflette in questo articolo.I ValueObject possono essere facilmente clonati con Object.create.I loro membri privati ​​sono immutabili.Ma che dire dei membri privati ​​modificabili?Se viene richiamato un set() sul clone, imposta l'oggetto prototipo originale all'interno della chiusura!Poiché il mio Object.recreate ricrea la chiusura, questo problema è risolto.

Quindi esiste un modo migliore per l'ereditarietà con variabili private?Perché tutti usano lo zucchero per creare lezioni?Ho letto così tanto sul prototipalismo che ancora non ne ho capito niente.

È stato utile?

Soluzione

Tornando su questo argomento dopo anni, posso dire che il codice che ho scritto allora era difettoso nel mescolare i concetti.JavaScript può effettivamente fornire vere variabili private mediante chiusura.Ma poiché i ValueObjects sono comunque immutabili, lo stato privato non può essere modificato e nasconderlo complica eccessivamente le cose.

Inoltre, l'ingegnoso Object.recreate è una sorta di "metodo factory" troppo astratto, che si dovrebbe dichiarare separatamente per ciascuna classe se ne è necessario.

Usa la composizione invece dell'ereditarietà!Crockford fornisce ottimi spunti JavaScript: https://crockford.com/javascript/prototypal.html

Altri suggerimenti

Penso che copia o clone sarebbe un nome migliore.Questo articolo spiega i meccanismi per la creazione di tali funzioni generiche.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top