Domanda

IL articolo di Wikipedia Di Legge di Demetra dice:

La legge può essere definita semplicemente come "usa un solo punto".

Tuttavia a semplice esempio di un interfaccia fluente potrebbe assomigliare a questo:

static void Main(string[] args)
{
   new ZRLabs.Yael.Pipeline("cat.jpg")
        .Rotate(90)
        .Watermark("Monkey")
        .RoundCorners(100, Color.Bisque)
        .Save("test.png");
}

Quindi va tutto d'accordo?

È stato utile?

Soluzione

Ebbene, la definizione breve della legge la accorcia troppo.La vera "legge" (in realtà consigli su una buona progettazione delle API) dice sostanzialmente:Accedi solo agli oggetti che hai creato tu stesso o che ti sono stati passati come argomento.Non accedere agli oggetti indirettamente tramite altri oggetti.I metodi delle interfacce fluenti spesso restituiscono l'oggetto stesso, quindi non violano la legge, se si utilizza nuovamente l'oggetto.Altri metodi creano oggetti per te, quindi non c'è nemmeno alcuna violazione.

Tieni inoltre presente che la "legge" è solo un consiglio sulle migliori pratiche per le API "classiche".Le interfacce fluenti rappresentano un approccio completamente diverso alla progettazione delle API e non possono essere valutate con la Legge di Demetra.

Altri suggerimenti

Non necessariamente."Usa solo un punto" è un riassunto impreciso della Legge di Demetra.

La Legge di Demetra scoraggia l'uso di più punti quando ciascun punto rappresenta il risultato di un oggetto diverso, ad esempio:

  • Il primo punto è un metodo chiamato da ObjectA, che restituisce un oggetto di tipo ObjectB
  • Il punto successivo è un metodo disponibile solo in ObjectB, che restituisce un oggetto di tipo ObjectC
  • Il punto successivo è una proprietà disponibile solo in ObjectC
  • verso l'infinito

Tuttavia, almeno a mio avviso, la Legge di Demetra non viene violata se l'oggetto restituito da ciascun punto è ancora dello stesso tipo del chiamante originale:

var List<SomeObj> list = new List<SomeObj>();
//initialize data here
return list.FindAll( i => i == someValue ).Sort( i1, i2 => i2 > i1).ToArray();

Nell'esempio precedente, sia FindAll() che Sort() restituiscono lo stesso tipo di oggetto dell'elenco originale.La Legge di Demetra non viene violata:la lista parlava solo con i suoi amici più stretti.

Detto ciò non tutto le interfacce fluenti violano la Legge di Demetra, purché restituiscano lo stesso tipo del chiamante.

Sì, anche se bisogna applicare un po’ di pragmatismo alla situazione.Prendo sempre la Legge di Demetra come linea guida invece che come regola.

Sicuramente potresti voler evitare quanto segue:

CurrentCustomer.Orders[0].Manufacturer.Address.Email(text);

magari sostituire con:

CurrentCustomer.Orders[0].EmailManufacturer(text);

Poiché molti di noi utilizzano ORM che generalmente presenta l'intero dominio come un oggetto grafico, potrebbe essere un'idea definire un "ambito" accettabile per un particolare oggetto.Forse dovremmo prendere la legge di Demetra per suggerire che non si dovrebbe mappare l'intero grafico come raggiungibile.

Lo spirito della Legge di Demetra è che, dato un riferimento a un oggetto o una classe, dovresti evitare di accedere alle proprietà di una classe che si trova a più di una sottoproprietà o metodo di distanza poiché ciò accoppierebbe strettamente le due classi, il che potrebbe essere involontario e può causare problemi di manutenibilità.

Le interfacce fluenti sono un'eccezione accettabile alla legge poiché lo sono significava essere almeno in qualche modo strettamente accoppiati poiché tutte le proprietà e i metodi sono i termini di un mini-linguaggio composti insieme per formare frasi funzionali.

1) Non lo viola affatto.

Il codice è equivalente a

var a = new ZRLabs.Yael.Pipeline("cat.jpg");
a = a.Rotate(90);
a = a.Watermark("Monkey");
a = a.RoundCorners(100, Color.Bisque);
a = a.Save("test.png");

2) Come dice il buon vecchio Phil Haack: La legge di Demetra non è un esercizio di conteggio dei punti

Non c'è problema con il tuo esempio.Dopotutto, stai ruotando, filigranando, ecc...sempre la stessa immagine.Credo che tu stia parlando continuamente con un oggetto Pipeline, quindi finché il tuo codice dipende solo dalla classe della Pipeline, non stai violando LoD.

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