Un consiglio su classe, sottoclasse....cosa è meglio.

di il
16 risposte

Un consiglio su classe, sottoclasse....cosa è meglio.

Ciao a tutti.
sono nuovo del forum e sto studiando c#.
Stavo facendo un esercizio trovato in rete, che chiede di creare un carrello per eCommerce.

L'esercizio dice: un carrello può contenere più Prodotti formati da Codice, Descrizione, Prezzo. In più, il carrello ha la Quantità, Sconto e il Prezzo per ogni Prodotto.

Questa cosa l'ho intesa come : (Prodotto Nel Carrello) fatto come CodiceProdotto, PrezzoUnitario, Quantità, Sconto PrezzoTotale(con sconto applicato se esiste).

Per fare questo ho creato una classe Prodotto {Codice, Descrizione, Prezzo} e una derivata ProdottoNelCarrello{propietà base + Quantità, Sconto, Prezzo}

questo è il codice

class Prodotto{ ecc.ecc.ecc......................}

class Carrello
    {
        class ProdottoNelCarrello : Prodotto //classe innestata , logicamente strettamente legata al carrello
                                             //info che hanno senso di esistere solo se il prodotto è presente nel carrello
                                             //informazioni aggiuntive quali "quantita", "sconto" e "prezzo totale" = (prezzo unitario * quantita * sconto)
        {
            public int Quantita { get; set; }
            public float Sconto { get; set; }
            public new float Prezzo { get; set; } //totale tra prezzo unitario e applicazione sconto

            public ProdottoNelCarrello(string codice, string descrizione, double prezzo) : base(codice, descrizione, prezzo) { }
        }

        private List<ProdottoNelCarrello> prodotti;

        public Carrello(){
            prodotti = new List<ProdottoNelCarrello>();
        }

        public void AggiungiProdotto(Prodotto prodotto, float sconto){
            ProdottoNelCarrello pc = prodotti.Find(p => p.Codice == prodotto.Codice);


ecc.ecc.ecc.            
IL mio dubbio sta nel fatto che non so se conveniva creare una Lista: private List<ProdottoNelCarrello> prodotti;
Oppure un Array che conteneva gli oggetti(Prodotto) con l'aggiunta di tre campi quantita, sconto e prezzo

Voi come avreste fatto?
Grazie.

PS: se volete, mi posto l'intero listato, cosi mi date suggerimenti per ottimizzazioni e altro.
Ari-grazie.

16 Risposte

  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    In questo caso, credo che l'ereditarietà OOP non sia applicata correttamente: vedere il prodotto nel carrello come una estensione del prodotto in sé mi pare una forzatura, soprattutto logica e quindi - come spesso accade - potrebbe diventarlo anche nel modello del codice.

    A mio avviso, l'approccio giusto è considerare queste tre entità:
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Alka ha scritto:


    A mio avviso, l'approccio giusto è considerare queste tre entità:
    Grazie per i consigli.
    Il testo dell'esercizio, non specificava nulla, se non di creare e gestire un carrello per eCommerce. Penso che sia stato lasciato allo studente (esercizio preso da un sito universitario, non ricordo quale) di usare quello che più ritenesse corretto.

    Quindi, tu vedresti questo esercizio come 3 classi separate? Nessuna eredita qualcosa dalle altre?
    L'oggetto creato su RigaCarrello, potrebbe essere un List o Dictionary o Array .....o HashSet che non permette duplicati(non saprei quale potrebbe essere migliore) all'interno della classe Carrello? (ogni carrello contiene un numero imprecisato di righe, ognuna per un solo prodotto)
    Io avevo pensato a questo esercizio come replica di quello che viene fatto in un supermercato.

    Entri nel supermercato, prendi un carrello e incominci a mettere prodotti all'interno. Giustamente invece, dovevo pensare in termini di sito, con righe di carrello.

    Sto studiando OOP e C# da poco, dopo anni di lavoro in linguaggi procedurali.
    Questo il testo dell'esercizio, per chi fosse curioso.

    Grazie.
    Progettare la struttura ad oggetti per gestire un carrello di un sito di e-commerce.
    Un carrello è associato all’utente collegato al sito, e per ogni utente è previsto un solo carrello.
    È importante risalire dall’utente al carrello e non il viceversa. L’utente è caratterizzato da 
    Username, Password (privato), Nome e Cognome. Ogni carrello può contenere diversi prodotti; 
    per ogni prodotto nel carrello è riportata la quantità,
    il prezzo, l’eventuale sconto applicato (in termini percentuali). Ogni prodotto è caratterizzato 
    da un codice, una descrizione, un prezzo. Dato un prodotto non è necessario risalire ai 
    carrelli in cui è stato aggiunto.
    
    Sul carrello è possibile eseguire le seguenti operazioni:
    
    Aggiungi prodotto
    Elimina prodotto
    Modifica di un prodotto già inserito
    Calcola totale
    Stampa a video del carrello (formato a piacere)
    Si noti che nel caso sia inserito un prodotto che già esiste nel carrello questo va a modificare 
    la quantità del prodotto precedentemente inserito.
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    CiSharpe ha scritto:


    Il testo dell'esercizio, non specificava nulla, se non di creare e gestire un carrello per eCommerce. Penso che sia stato lasciato allo studente (esercizio preso da un sito universitario, non ricordo quale) di usare quello che più ritenesse corretto.
    La mia precisazione era legata al fatto che mi è già capitato qualche esercizio dove si dovesse procedere forzatamente con una soluzione, e magari lo scenario proposto non era (per esperienza) adatto a quella soluzione.

    E' successo pure al mio esame di maturità, anni e anni fa, quindi davo per scontato potesse accadere di nuovo...

    CiSharpe ha scritto:


    Quindi, tu vedresti questo esercizio come 3 classi separate? Nessuna eredita qualcosa dalle altre?
    Non ne vedo l'esigenza.

    CiSharpe ha scritto:


    L'oggetto creato su RigaCarrello, potrebbe essere un List o Dictionary o Array .....o HashSet che non permette duplicati(non saprei quale potrebbe essere migliore) all'interno della classe Carrello? (ogni carrello contiene un numero imprecisato di righe, ognuna per un solo prodotto)
    La classe Carrello potrebbe contenere un Dictionary di oggetti RigaCarrello, dove la chiave potrebbe essere il codice del prodotto inserito in quella riga: questo renderebbe più veloce individuare la possibile presenza del prodotto all'interno del carrello, allo scopo di aumentarne la quantità, oppure inserendolo se mancante.

    Riporto un po' di codice a titolo esemplificativo, con una idea di quello che dicevo, chiaramente parziale (manca la rimozione dal carrello, il decremento della quantità) ma dovrebbe essere sufficiente a rendere l'idea.
    
    /// <summary>
    /// Rappresenta un singolo prodotto disponibile nel negozio.
    /// </summary>
    public class Prodotto
    {
    	public string Codice { get; set; }
    	public string Descrizione { get; set; }
    	public decimal PrezzoUnitario { get; set; }
    }
    
    /// <summary>
    /// Rappresenta una riga di prodotto del carrello.
    /// </summary>
    public class RigaProdotto
    {
    	public Prodotto Prodotto { get; set; }
    	public decimal Quantita { get; set; }
    	
    	public decimal GetPrezzoRiga()
    	{
    		return Prodotto.PrezzoUnitario * Quantita;
    	}
    }
    
    /// <summary>
    /// Rappresenta il carrello dell'utente e i suoi contenuti.
    /// </summary>
    public class Carrello
    {
    	public Carrello()
    	{
    		Righe = new Dictionary<string, RigaProdotto>();
    	}
    	
    	public RigaProdotto AggiungiProdotto(Prodotto prodotto, decimal quantita)
    	{
    		if (!Righe.TryGetValue(prodotto.Codice, out var rigaProdotto))
    		{
    			rigaProdotto = new RigaProdotto()
    			{
    				Prodotto = prodotto,
    				Quantita = quantita
    			};
    			
    			Righe.Add(prodotto.Codice, rigaProdotto);
    		}
    		else
    		{
    			rigaProdotto.Quantita += quantita;
    		}
    		
    		return rigaProdotto;
    	}
    	
    	public decimal GetTotaleImponibile()
    	{
    		return Righe.Values.Sum(o => o.GetPrezzoRiga());
    	}
    
    	public decimal GetTotaleIva()
    	{
    		return GetTotaleImponibile() / 100 * AliquotaIva;
    	}
    
    	public decimal GetTotaleCarrello()
    	{
    		return GetTotaleImponibile() + GetTotaleIva();
    	}
    
    	public decimal AliquotaIva { get; set; }
    	public Dictionary<string, RigaProdotto> Righe { get; set; }
    }
    
    Ciao!
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Perfetto grazie.
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Alka ha scritto:



    Ciao!
    Ciao.
    rieccomi. C'è una cosa che non ho capito e spero possiate fare ordine nella mia testa.
    Riguardo l'esercizio che stavo facendo vorrei implementare questa cosa per rendere tutto più robusto.

    La classe Prodotto è public ,
    La classe Utente è public, e fino a qui è OK.

    Ora vorrei che la classe Carrello fosse "visibile" (o istanziabile) solo dalla classe Utente (la classe Program con il suo Main non deve vederla)
    Inoltre la classe RigaCarrello, vorrei fosse visibile solo dalla classe Carrello, neanche l'Utente può vederla.

    Ho le classi tutte in file diversi e in un unico namespace.
    Ora come si sa, non posso cambiare il modificatore che può essere solo public o internal.

    Per fare quello che ho detto, devo spostarle in sottocartelle, in un altro namespace....booh!
    O basta creare classi innestate tipo
    
    public class Utente{
        [internal? / protected ? Private? ] class Carrello{
            class RigaCarrello {
            }
        }
    }
    


    L'accessibilità continua a essere una cosa oscura...
    Grazie, ciao
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    CiSharpe ha scritto:


    Riguardo l'esercizio che stavo facendo vorrei implementare questa cosa per rendere tutto più robusto.
    Nessuna delle cose a cui hai pensato contribuisce a rendere più robusta l'architettura.

    Vuoi creare un software affidabile? Usa classi public e crea progetti di Unit/Integration Testing che esercitino i loro metodi e verifichino che, partendo da un input, restituiscano l'output richiesto, poi ripeti la cosa combinando assieme una o più classi, fino a testare in modo automatizzato che il sistema funzioni così come ci si aspetta.

    Questa "blindatura" non ha alcuna ragione di essere, oltre a creare diverse problematiche nella scrittura del codice: magari si deve accedere a un campo e il suo tipo, essendo privato, non è raggiungibile, ma questo non è prevedibile a priori o comunque richiede più modifiche al codice per alterare la visibilità di tipi di dati che non avrebbero mai dovuto essere occultati.

    Il fatto invece di proteggere una implementazione o usare proprietà e campi sfruttando l'incapsulazione, quindi rendendo "privati" i membri e i metodi di una classe, è tutta un'altra questione.

    Dai un'occhiata anche ad altre librerie opensource che puoi trovare liberamente su GitHub e come sono state realizzate: da nessuna parte troverai l'applicazione di chiusure simili, del tutto inefficaci, tranne ovviamente dove possono avere un senso.

    CiSharpe ha scritto:


    L'accessibilità continua a essere una cosa oscura...
    No, l'accessibilità è una cosa ben definita e documentata: è sufficiente studiare per capire quali sono i livelli applicabili e qual è l'effetto rispetto al resto, che si parli di classi o di membri, ma non c'è nulla di misterioso o di "oscuro".

    Ciao!
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Alka ha scritto:


    CiSharpe ha scritto:


    Riguardo l'esercizio che stavo facendo vorrei implementare questa cosa per rendere tutto più robusto.
    Nessuna delle cose a cui hai pensato contribuisce a rendere più robusta l'architettura.
    Perfetto.
    Quindi per rendere un programma "robusto", si agisce sempre sui metodi, in modo da evitare quante più eccezioni possibili.

    La mia era un domanda puramente didattica, nel senso, è possibile relazionare le classi come si fa con i database?
    Esempio, condizione fondamentale: "Non avere un oggetto Carrello se non esiste un oggetto Utente istanziato e l'oggetto Carrello deve essere referenziato solo all'interno dell'oggetto Utente"

    Grazie per essere sempre disponibile.
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    CiSharpe ha scritto:


    Quindi per rendere un programma "robusto", si agisce sempre sui metodi, in modo da evitare quante più eccezioni possibili.
    Diciamo che il termine "robusto" è un po' troppo generico e astratto se riferito a un programma, perché non è chiaro a cosa si fa riferimento: si parla dell'accuratezza con cui si prevengono e risolvono i bug? si parla di come il programma sia affidabile e poco incline a crashare? si parla di sicurezza interna e protezione rispetto ai dati e alle istruzioni?

    E' un termine che escluderei sostituendolo con qualcosa di più specifico, giusto per essere chiari sull'aspetto verso il quale si sta ponendo l'attenzione.

    Detto questo, le eccezioni non sono da evitare. E' come dire che si dovrebbe evitare una multa: certo, dal punto di vista di un trasgressore sono una scocciatura, ma è una garanzia per gli altri che magari non si trovano il passo carrabile occupato dall'auto di un estraneo. Le eccezioni sono uno strumento che nasce per segnalare una condizione tale per cui il programma non può proseguire: può essere gestita oppure no, e ciò può essere fatto bene oppure male. Se si costruisce una libreria, fare uso delle eccezioni è opportuno. Chi la usa per sviluppare applicazioni può decidere di intercettarle e dare un messaggio significativo all'utente, o creare un programma resiliente tentando di risolvere il problema, o ignorarlo. In ogni caso, sollevare 1, 10, 100 eccezioni non renderà un programma né più né meno robusto di altri (se la gestione predefinita interviene, presenta il messaggio e consente la prosecuzione del programma stesso, senza terminarlo).

    Mi pare che si stia buttando nel calderone concetti ed elementi della programmazione che vanno prima approfonditi e su cui è necessario maturare una certa esperienza, poi sarà sicuramente possibile specularci e filosofeggiarci sopra.

    CiSharpe ha scritto:


    La mia era un domanda puramente didattica, nel senso, è possibile relazionare le classi come si fa con i database?
    Anche qui, dipende dal database: non tutti sono esclusivamente SQL e basati sul modello E/R.
    Oltre a questo, non è detto che riprodurre un modello E/R precisamente sia proficuo nello sviluppo di una applicazione, tant'è vero che esistono molteplici tool di ORM per rendere la struttura rigida del database fruibile dal linguaggio di programmazione.

    CiSharpe ha scritto:


    Esempio, condizione fondamentale: "Non avere un oggetto Carrello se non esiste un oggetto Utente istanziato e l'oggetto Carrello deve essere referenziato solo all'interno dell'oggetto Utente"
    La creazione degli oggetti è sempre possibile. E' chiaro che se nel costruttore della classe Carrello inserisco come parametro l'Utente di riferimento e lo rendo obbligatorio (sollevo eccezione se null), sarà necessario per forza avere un utente prima di poter creare il Carrello.

    Detto in altri termini, in questo modo l'associazione con un utente è fondamentale per poter creare il carrello, in quanto la creazione del carrello presuppone di passare come parametro l'utente a cui esso appartiene.

    Quindi l'istanza del Carrello non deve essere referenziato all'interno dell'Utente, bensì il contrario.

    E' bene precisare che qui si sta discutendo di "legami" tra oggetti che vengono instaurate in base all'uso di specifici costrutti (o pattern): non ci sono parole chiave per configurare le classi in modo da sapere con quali altre classi possono entrare in contatto o che relazioni ci saranno poi tra gli oggetti, ma tutto dipende da come il codice viene scritto.

    Ad ogni modo, come già dicevo nel messaggio precedente, questo tipo di "forzature" sarei molto restio a implementarle, poiché comporta la creazione di gerarchie complesse dove invece di aver diversi oggetti che si referenziano e che contengono ciascuno le informazioni di competenza, arrivo invece ad avere una "radice" tra l'altro probabilmente errata la quale costituisce un percorso obbligato da fare per accedere e ottenere tutte le restanti informazioni che sono all'interno (ad esempio, nello scenario che proponi, devo disporre dell'oggetto utente per poter accedere a un carrello al suo interno, e non ne vedo lo scopo).

    Ciao!
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Alka ha scritto:



    Ciao!
    perfetto tutto chiaro.
    grazie ancora
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    CiSharpe ha scritto:


    Per fare quello che ho detto, devo spostarle in sottocartelle, in un altro namespace....booh!
    La questione mi incuriosiva, ed ho fatto un tentativo (non che non mi fidassi di Alka, ovviamente ):
    public class Utente
    {
        public Carrello Carrello { get; set; }
        public Utente() { }
        private class Carrello
        {
             private Carrello() { }
        } 
    }
    L'intellisense ha detto ciccia! Ben due errori di compilazione: CS0053 e CS0102 (ma il secondo sarebbe facilmente aggirabile)
    Non si può (per i motivi che spiegava Alka) dichiarare una proprietà public, se detta proprietà appartiene ad una classe private.

    Gli Unit Test li ho scoperti da poco, ma ora che ci sto prendendo la mano penso che siano la cosa più figa dell'universo. Soprattutto per me che scrivo due metodi, poi faccio altro per giorni e poi cerco di scrivere latri due metodi. Combino sempre corbellerie, e invece così le scovo subito e risparmio un mare di tempo.
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Sgrubak ha scritto:


    Non si può (per i motivi che spiegava Alka) dichiarare una proprietà public, se detta proprietà appartiene ad una classe private.
    E questo ha ovviamente senso: chi potrebbe mai usare una proprietà public, quindi accessibile ovunque e da qualsiasi altra classe, se non ha accesso al tipo corrispondente?

    Diciamo che l'errore di compilazione conferma la restrizione specifica, ma io partivo già dal principio più ampio che una simile restrizione, implementata senza una ragione specifica, non ha motivo di essere e andrebbe evitata, o comunque non partecipa a nessun criterio di maggiore stabilità, solidità o altri aspetti affini del programma.

    Ciao!
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Alka ha scritto:


    E questo ha ovviamente senso: chi potrebbe mai usare una proprietà public, quindi accessibile ovunque e da qualsiasi altra classe, se non ha accesso al tipo corrispondente?
    Li per li mi ha accarezzato l'idea che la classe Carrello, se private dentro Utente potesse funzionare. Ma in effetti se è private, è private... Non ci sono storie. Per definizione non è visibile all'esterno. Mi mancava quel pezzo di ragionamento, ma il compilatore ha rimediato.

    Grazie della spiegazione!
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    Ciao.

    Per prendere sempre più confidenza col C#, ho provato a rifare il programma con classi innestate e funziona tutto.
    Poi ovviamente, come mi dicevi ha poco senso e la gestione sarebbe molto più complicata.
    Per evitare che un carrello venga istanziato per errore da altri programmatori, basta rigirare la "dipendenza" (non so se si chiama cosi), mettere un oggetto Utente nella classe Carrello e bloccare tutto se Utente è NULL. (e non il contrario come ho fatto io)

    questo il listato. Dal Main principale, posso solo vedere Utente --> che vede Carrello --> che vede RigaCarrello.

    Da qui la domanda.
    Quando ha senso creare delle classi innestate? (non è questo il caso come mi hai fatto vedere)

    Se volete dare un'occhiata
    
        class Program
        {
            static void Main(string[] args)
            {
                Prodotto prodotto1 = new Prodotto() { Codice = "P1", Descrizione = "Prodotto UNO", Prezzo = 254 };
                Prodotto prodotto2 = new Prodotto() { Codice = "P2", Descrizione = "Prodotto DUE", Prezzo = 59 };
    
                Utente utente = new Utente("Utente");
                utente.AggiungiProdotto(prodotto1, 0);
                utente.AggiungiProdotto(prodotto2, 0);
                utente.AggiungiProdotto(prodotto1, 80);
                utente.AggiungiProdotto(prodotto2, 10);
            }
        }
    
        class Prodotto
        {
            public string Codice { get; set; }
            public string Descrizione { get; set; }
            public float Prezzo { get; set; }
        }
    
        class Utente
        {
            public string Nome { get; set; }
            private Carrello carrello;
    
            public Utente(string nome)
            {
                Nome = nome;
                carrello = new Carrello();
            }
    
            public void AggiungiProdotto(Prodotto p, float s)
            {
                carrello.AggiungiAlCarrello(p, s);
            }
            //************************************************************************
            //************************************************************************
            //************************************************************************
            //************************************************************************
            class Carrello
            {
                List<RigaCarrello> prodotti = new List<RigaCarrello>();
                public void AggiungiAlCarrello(Prodotto p, float s)
                {
                    if (prodotti != null)
                    {
                        RigaCarrello riga = prodotti.Find(rc => rc.prodotto.Codice == p.Codice);
                        if (riga != null)
                        {
                            riga.SetQuantita(riga.GetQuantita() + 1);
                            riga.SetSconto(s);
                        }
                        else
                            prodotti.Add(new RigaCarrello(p, 1, s));
                    }
                    else
                        prodotti.Add(new RigaCarrello(p, 1, s));
    
    
    
                    foreach (RigaCarrello rc in prodotti)
                    {
                        Console.WriteLine(rc.prodotto.Descrizione + "-" + rc.GetQuantita() + "-" + rc.GetSconto() + "-" + rc.GetPrezzo());
                    }
                    Console.WriteLine("\n\n");
                }
    
    
    
                //************************************************************************
                //************************************************************************
                //************************************************************************
                class RigaCarrello
                {
                    public Prodotto prodotto { get; }
                    private int quantita;
                    private float sconto;
                    private double valoreSconto; // Prodotto.prezzo * sconto
                    private double prezzoScontato; // Prodotto.prezzo * sconto
                    private double prezzo;// Prodotto.prezzo * quantità * sconto
    
                    public RigaCarrello(Prodotto p, int q, float s)
                    {
                        prodotto = p;
                        quantita = q;
                        sconto = s;
                        CalcolaPrezzo();
                    }
                    private void CalcolaPrezzo()
                    {
                        valoreSconto = prodotto.Prezzo * sconto / 100;
                        prezzoScontato = prodotto.Prezzo - valoreSconto;
                        prezzo = prezzoScontato * quantita;
                    }
                    public int GetQuantita()
                    {
                        return quantita;
                    }
                    public void SetQuantita(int q)
                    {
                        quantita = q;
                        CalcolaPrezzo();
                    }
                    public float GetSconto()
                    {
                        return sconto;
                    }
                    public void SetSconto(float s)
                    {
                        sconto = s;
                        CalcolaPrezzo();
                    }
                    public double GetPrezzo()
                    {
                        return prezzo;
                    }
                }
            }
        }
    
  • Re: Un consiglio su classe, sottoclasse....cosa è meglio.

    CiSharpe ha scritto:


    Quando ha senso creare delle classi innestate?
    Creare classi innestate ha senso solo quando esse costituiscono meramente un dettaglio implementativo della classe più ampia e si vuole nascondere tale dettaglio.

    Ribadisco che, dal mio punto di vista, nel caso in esame non ha senso creare queste classi innestate, non hanno motivo di esistere.

    Quando il modello di classi che hai costruito verrà ad esempio utilizzato in una applicazione Web, e sarà necessario visualizzare un carrello, comprese le singole righe al loro interno, e magari leggere e scrivere un carrello su disco a prescindere dalla sua associazione con un utente, dovrai rivederlo completamente.

    Il fatto che un Carrello debba essere associato a un utente, come si era detto, non significa che la classe Utente debba istanziarlo.

    Queste classi sono il classico esempio di DTO (Data Transfer Objects), ovvero classi che nascono con l'obiettivo di trasferire dati e semplificare alcuni calcoli: incastonarle l'una nell'altra, rendere la creazione dell'una dipendende da un'altra e "privatizzarne" alcune è solo un passo verso un modello più imbrigliato, restrittivo, più prono a modifiche per esigenze successive e legato a una elevatissima coesione dei suoi componenti.

    E' come se tu dovessi realizzare un trapano e avessi incollato assieme batteria, corpo, mandrino e punta, rendendoli insostituibili, solo per il timore che qualcuno lo possa smontare, di fatto rendendo il sistema in sé meno modulare.

    Ciao!
Devi accedere o registrarti per scrivere nel forum
16 risposte