Officina meccanica. Definizione del problema e specifica dei requisiti

Dimensione: px
Iniziare la visualizzazioe della pagina:

Download "Officina meccanica. Definizione del problema e specifica dei requisiti"

Transcript

1 Officina meccanica Rev Novembre 2007 Esempio di esercizio: analizzare, progettare e sviluppare. Per l analisi e il progetto si usi UMLStar, per lo sviluppo Eclipse. Questo esempio deriva dalla prova di esame del 14/12/2006. Definizione del problema e specifica dei requisiti Un officina meccanica dispone di un magazzino in cui tiene le parti di ricambio. Ogni parte è descritta in un catalogo tramite un numero identificativo univoco (ID) e da una descrizione testuale. Una parte può essere un complesso (p.e., un motore) o una parte elementare (p.e., una vite). Un complesso può a sua volta essere costituito da altri complessi (p.e., il sistema di distribuzione, il carburatore, ecc.) e/o parti elementari (l iniettore, la flangia, ecc.). Il catalogo è organizzato a partire dai differenti tipi di auto e consente la ricerca di una specifica parte procedendo dal tipo di auto, attraverso un complesso, una sottoparte, ecc.... fino alla parte desiderata. Le auto non sono da considerare come parti: esse sono nel catalogo solo come elementi di classificazione e non come parti a magazzino. Ai fini della gestione del magazzino viene tenuta traccia della disponibilità (dispo) di ogni singola parte presente. In altre parole, ciascun elemento nel catalogo ha un attributo che dice quanti esemplari sono presenti di esso in magazzino. Quando il meccanico/magazziniere preleva una o più parti dal magazzino la disponibilità viene decrementata corrispondentemente. Per evitare che l officina resti sguarnita per effetto dei prelievi, il sistema provvede ad effetture gli ordini di reintegro in modo automatico. A tale scopo, per ogni parte è prevista una soglia (minima). A fine giornata, il sistema verifica se ci sono parti la cui disponibilità è inferiore al valore di soglia. Per le parti al di sotto della soglia, per le quali non è già stato già fatto un ordine (ovviamente in giorni antecedenti), viene costruito un ordine che le comprende tutte. Per ciascuna parte è prevista la quantità da ordinare (qdaordinare), per cui, relativamente a una data parte, l ordine contiene sempre quel quantitativo. Le parti al di sotto della soglia, per le quali è già stato effettuato un ordine non vengono considerate. Per semplicità si trascuri l intestatario dell ordine, assumendo che l officina lavori per una sola marca e che gli ordini vengano diretti sempre alla casa madre. Un ordine ha una data e un numero progressivo. Esso resta presente nel sistema fino al momento in cui le parti non vengono reintegrate. Sempre per ragioni di semplicità, si assuma che, quando le parti contenute in un dato ordine vengono consegnate al magazzino, la consegna comprenda tutte quante le parti specificate nell ordine, in modo che non vi siano rimanenze di ordine da soddisfare. 1. Utilizzando StarUML: Si costruisca il modello UML del dominio applicativo, evidenziando gli attributi delle classi e i metodi che risultano dai diagrammi dei punti seguenti. Si tracci il diagramma di sequenza relativo alla ricerca della parte x, appartenente al complesso y (che a sua volta può appartenere al complesso z,...) del tipo di auto a. 1 La sequenza deve concludersi con il prelievo di k 1 esemplari della parte trovata (se ci sono). Si tracci il diagramma di sequenza relativo all eventuale emissione automatica dell ordine di reintegro (il diagramma deve identificare inequivocabilmente qual è l attore). Si generino i template delle classi. 1 Nel sistema reale questa operazione verrà fatta tramite interfaccia interattiva. Nel nostro caso si immagini di fare un interrogazione passando a, z, y e x come parametri. Si assuma che questi parametri rappresentino la descrizione delle parti. 1

2 2. Utilizzando Eclipse: importare le classi generate da StarUML e costruire il programma, che consenta le funzionalità di cui sopra. In particolare: (a) Prevedere almeno due package: (a) dominio per le classi appartenenti al dominio e (b) applicazione contenenti le classi applicative. Il package applicazione deve contenere un Main che chiama all occorrenza i metodi delle classi applicative. (b) Preveda il metodo stampa() (presumibilmente nella classe Catalogo e in altre) che stampi ordinatamente (con le relative disponibilità) le entità di dominio presenti al momento della chiamata del metodo stesso. Questo metodo viene molto comodo per testare non solo il Builder (vedi sotto), ma anche le altre funzionalità. (c) Nel package client prevedere la classe Builder per popolare il modello. Il modello va popolato in questo modo: tipi di auto: Panda1000, Punto1200, Punto1600. motore per Panda1000, motore per la Punto1200, motore per la Punto1600. Per tutti questi complessi si ponga dispo = 2. carburatore aspirato (carba) (dispo = 2), utilizzabile sia su Panda1000 che su Punto Il carburatore aspirato ha queste sottoparti (disponibili individualmente): corpo (corpcarba) (disponibilità =1) valvola a farfalla (vfarf) (disponibilità =3) carburatore a iniezione (carbi)(disponibilità =3), utilizzabile su Punto1600, composto dalle seguenti parti (disponibili individualmente): corpo (corpcarbi) (disponibilità =2) iniettore (iniettore) (disponibilità =3) (d) A partire dal modello popolato ricercare e prelevare 2 valvole a farfalla 2. (e) Effettuare la verifica di fine giornata, eventualmente generando l ordine. Per lo svolgimento delle funzionalità dei punti (2d) e (2e) si suggerisce di prevedere apposite classi applicative. 1 Osservazioni La specifica precedente contiene molte semplificazioni rispetto al caso reale. Per ora ci applicheremo a lavorare su di essa. Al Paragrafo 5 verranno introdotte alcune modifiche in modo da rendere l esempio più realistico. In base alle specifiche il sistema deve avere un catalogo per tenere traccia delle parti disponibili in magazzino. Si osservi che non si tratta di una idea completamente peregrina, anche se in un sistema reale il catalogo e il magazzino potrebbero essere distinti. Quando si dice catalogo e magazzino ci si riferisce al catalogo informatico e al magazzino informatico: il vero catalogo sarà probabilmente di carattere informatico 3, il vero magazzino è una una cosa molto complessa fatta di locali, spazi, depositi e oggetti in esso contenuti. Dal punto di vista della modellazione il nostro magazzino è un elenco di parti, supplementate dalla loro disponibilità ed eventualmente altre informazioni (come ad esempio la dislocazione delle parti negli spazi del magazzino). Dunque catalogo e magazzino si possono ridurre ad un unica entità, aggiungendo al catalogo le informazioni necessarie alla gestione del magazzino. Una possibile differenza certamente esiste: il fatto che non tutto quello che è nel catalogo viene necessariamente tenuto nel magazzino. In tal senso il nostro sistema presenta già questa differenziazione in quanto le auto sono nel catalogo ma non nel magazzino. Su questo ed altri aspetti torneremo al Paragrafo 5. Il catalogo è una struttura gerarchica (ad albero) che prevede al primo livello i differenti tipi di auto. Per le auto non ha significato parlare di disponibilità. Le auto non sono in magazzino e quindi non sono da considerare come parti. Vale la pena di rimarcare che il nostro catalogo/magazzino contiene parti complesse (un motore) e parti elementari (una vite). Il motore costituisce una parte e quindi avrà un suo ID. La vite costituisce una differente parte e quindi essa pure avrà un suo ID. Ai fini del magazzino, le viti che fanno parte di un motore non sono 2 Come osservato in precedenza la ricerca deve passare per Panda1000 (o Punto1200), relativo motore e carburatore. 3 In passato nelle officine meccaniche esistevano cataloghi di varia natura, cartacei o con rappresentazioni fotografiche annotate, presentate attraverso speciali visori 2

3 parti a sé stanti, ovvero: si assume che non accadrà mai che una vite venga prelevata dal magazzino svitandola da un motore. 4 Un altro aspetto da precisare è quello della costruzione degli ordini. L ordine viene prodotto automaticamente a fine giornata. Questo ci dice che l attore che determina la costruzione dell ordine è il tempo. Nel costruire l ordine seguiremo la strada più ovvia, anche se non proprio efficiente: esaminare la disponibilità di tutte le singole parti e includere nell ordine quelle per cui c è stato lo sforamento della soglia in giornata, ovvero per quelle che sono sotto la soglia e non sono già in un precedente ordine (fatto, evidentemente, in giorni precedenti). Al paragrafo 5 introdurremo un modo più intelligente (meno costoso) per arrivare all ordine. Come osservato in precedenza ogni parte ha un ID univoco. Le parti sono anche rappresentate dalla loro descrizione. Se questa è univoca la si può usare per identificare le parti, rendendo non strettamente necessario l ID. Ma, come vedremo in seguito, si presenterà la necessità di distinguere tra parti elementari e parti complesse. La distinzione potrebbe essere attuata ricorrendo al costrutto del linguaggio instanceof. Più semplicemente, le parti elementari possono essere discriminate dai complessi attraverso l ID. A tal fine basta stabilire una convenzione. Ad esempio: si può stabilire che le parti elementari hanno un ID maggiore o uguale a n (o che comincia con 0), mentre i complessi hanno un ID inferiore (o che comincia con una cifra diversa da 0). Nel seguito assumeremo che le parti elementari abbiano ID 100 Si noti che in questo sistema, una volta che il catalogo è stato costruito, le uniche variazioni riguardano la disponibilità delle singole parti e la costruzione/eliminazione di ordini. Le disponibilità variano solo all atto del prelievo/reintegro. 2 Modello di dominio Il modello di dominio prevede necessariamente la classe Catalogo che fa da contenitore a tutto il resto. La classe Catalogo, per come è specificato il problema, contiene (ha sotto di sé) i tipi di auto (Auto). Un tipo di auto ha sotto di sé le parti, esse pure organizzate gerarchicamente (c è da aspettarsi che sotto l auto ci siano parti complesse di primo livello quali: il motore, la trasmissione, l impianto elettrico, la meccanica generica, ecc.). Ogni parte può essere un complesso o una parte elementare. Se si tratta di un complesso esso conterrà altre parti; se si tratta di una parte elementare siamo ad una foglia dell albero di rappresentazione del catalogo. Con tutta evidenza, la struttura delle parti è descritta dal pattern Composite. In Figura 1 viene dato il diagramma UML di quanto è stato fin qui descritto. Figura 1: Modello di partenza. 4 Se si ammette la cannibalizzazione la complessità del sistema aumenta di molto (occorre tener traccia di quanto una data parte è stata cannibalizzata, come si reintegra ecc.). 3

4 Il modello di Figura 1 non considera gli ordini. Per tener conto degli ordini basta semplicemente legare la classe Ordine alla classe Parte come in Figura 2. Questo schema consente di verificare se per una data parte sotto la soglia è già stato emesso o meno l ordine di reintegro. La specifica del problema stabilisce che quando le parti contenute in un ordine vengono reintegrate l ordine viene eliminato. Ciò rende univoca la relazione tra ordini e parti sotto la soglia. Il modello di Figura 2 risponde pienamente alle specifiche del problema. Si notino gli attributi risultanti dall analisi fin qui svolta. Figura 2: Aggiunta deli ordini al modello. Il modello di Figura 2 è debole dal punto di vista della navigabilità. Infatti se l officina vuole sapere quali parti sono in ordine, ovvero quanti ordini sono stati emessi e non ancora soddisfatti, occorre navigare il modello, passando attraverso le parti fino agli ordini e dal contenuto di questi ultimi vedere quali sono le parti in ordine. La stessa verifica che una parte in numero inferiore alla soglia sia stata o meno ordinata non è la più naturale: infatti richiede di verificare se la parte è legata a un ordine. Un modo più naturale per tenere traccia degli ordini e delle loro relazioni con le parti consiste nel prevedere entro le parti la variabile (booleana) inordine che indichi se la relativa parte è o meno già stata ordinata. Con queste considerazioni il modello si trasforma in quello di Figura 3. Nello schema di Figura 3 è stata introdotta la classe Officina (che verrà istanziata come singleton, come del resto verranno istanziate come singleton la classe Catalogo e altre classi descritte in seguito). L oggetto della classe Officina diventa il nuovo contenitore. Da esso si accede direttamente gli ordini e da questi si arriva alle parti (già ordinate). 5 3 Costruzione iniziale del programma e popolazione del modello Prima di procedere con l analisi conviene soffermarsi sulla costruzione del grafo degli oggetti derivante dal modello di Figura 3 e sulla popolazione del modello stesso come richiesto. A tale scopo la specifica prevede la costruzione della classe Builder, separata dal Main. 6 5 Naturalmente si poteva fare a meno della nuova classe Officina, legando gli ordini direttamente al catalogo, ottenendo però un modello artificioso, in quanto di per sé il catalogo non ha niente a che fare con gli ordini. Lo schema di Figura 3 corrisponde meglio di quello di Figura 2 alla effettiva struttura del dominio. 6 Come abbiamo osservato la classe Builder (come Officina e Catalogo) dovrebbe essere un singleton. Nello svolgere questo esercizio faremo a meno di tenere conto dei singleton, assumendo che la trasformazione in singleton (di cui non ci occuperemo) venga rimandata a più avanti. 4

5 Figura 3: Modifica al modello per una miglior gestione degli ordini. Stabiliamo che la classe Builder esponga il metodo build() avente la funzione di popolare il grafo inizialmente. Prevediamo anche il metodo getofficina() che restituisce l officina creata da build(). Mentre in Officina viene previsto il metodo getcatalogo() che restituisce il catalogo. Conseguentemente main() inizierà nel modo seguente: 7 // parte iniziale del metodo main() Builder b = new Builder(); b.build(); Officina officina = b.getofficina(); Catalogo cat = officina.getcatalogo(); Per le classi del modello dovremo prevedere i necessari metodi getter e setter, per leggere/scrivere i relativi attributi. La classe Parte è astratta. Essa definisce attributi e metodi getter/setter per le classi derivate. Per la classe Catalogo occorre prevedere il metodo addauto(), chiamato da Builder per aggiungere un auto a catalogo. Per la classe Auto occorre prevedere il metodo addpart() per aggiungere una parte all insieme parti. Analoghi metodi servono nella classe Complesso (per aggiungere parti al complesso), nella classe Officina (per aggiungere ordini), nella classe Ordine (per aggiungere parti). Nell implementare il modello conviene appoggiarsi a una struttura dell interfaccia API di Java. Nel codice allegato si fa ricorso alla struttura ArrayList (iterabile, serializzabile e altro). Nella dichiarazione del problema si suggeriva di costruire un metodo per la stampa del catalogo. Ovviamente tale metodo farà parte di Catalogo. Esso provvederà direttamente a stampare le auto che sono nel catalogo e delegherà le auto a stampare le parti (complessi) sotto di esse. Queste, a loro volta, stamperanno le parti in esse contenute e le delegheranno alla stampa delle parti sottostanti. Il processo di passaggio della delega deve aver termine con le parti elementari, nel senso che esse non devono essere delegate. Per poter stabilire facilmente se una parte è o no elementare, si usa l attributo ID. Se ID 100 la parte è elementare. In base ai precedenti ragionamenti i metodi di stampa del catalogo nelle differenti classi prendono la forma seguente. 8 In Catalogo public void stampa(){ //stampa le auto if (auto.isempty()) return; for (int i=0; i<auto.size(); i++){ 7 Conviene rendere disponibile il catalogo anche al Main per evitare di doverlo richiedere ogni volta all officina. 8 Si osservi che l uso dell iteratore sarebbe stato più elegante rispetto al costrutto for. 5

6 Auto a = auto.get(i); System.out.println("ID = "+a.getid() + " a.stampa(); "+a.getdescr()); In Auto public void stampa(){ //stampa le parti sotto auto if(parti.isempty()) return; for(int i=0; i<parti.size(); i++){ Parte p = parti.get(i); System.out.println(" ID = " + p.getid()+ " " Disponibilità = "+p.getdispo()); if (p.getid()< 100) { p.stampa(); "+ p.getdescr()+ In Complesso public void stampa() { //stampa le parti di un complesso if (parti.isempty()) return; for (int i=0; i<parti.size(); i++){ Parte p = parti.get(i); System.out.println(" ID = " + p.getid()+ " "+ p.getdescr()+ " Disponibilità = "+p.getdispo()); if (p.getid()< 100) { p.stampa(); Il metodo stampa() di Complesso è l implementazione del metodo astratto stampa() di Parte. 9 Lo stesso metodo viene implementato come vuoto nella classe ParteElementare. Il metodo stampa() di Catalogo può essere chiamato ad ogni occorrenza. In particolare, nella classe Build, ogni volta che viene aggiunto un elemento al catalogo la chiamata di stampa() mostra se l elemento è stato inserito correttamente. Ad esempio: 10 // in build() dopo aver istanziato il Catalogo come cat Auto panda1000 = new Auto(1, "Panda1000"); cat.addauto(panda1000); cat.stampa(); Parte motorepanda = new Complesso(10, "motore Panda1000", 2); panda1000.addpart(motorepanda); cat.stampa(); Parte carba = new Complesso(20, "Carburatore aspirato", 2); motorepanda.addpart(carba); cat.stampa(); Parte vfarf = new ParteElementare(102, "Valvola a Farfalla", 3); carba.addpart(vfarf); cat.stampa(); 9 Incidentalmente vale la pena di osservare che il metodo stampa() di Auto e di Complesso sono identici. 10 Il costruttore delle auto ha come parametri ID e la descrizione; il costruttore di una parte ha come parametri ID, la descrizione e la disponibilità (iniziale). 6

7 Al termine di questa digressione relativa alla costruzione e popolazione del modello possiamo tornare ad esaminare lo svolgimento delle funzionalità richieste. Prima però osserviamo che la digressione ci ha portato a identificare alcuni metodi delle classi del modello, necessari ai fini della navigazione, della lettura e dell assegnazione di valori agli attributi degli oggetti che fanno parte del modello stesso. 4 Casi d uso e loro realizzazione In Figura 4 vengono mostrati i casi d uso di interesse. Si noti che il prelievo di una parte è un estensione del caso d uso di ricerca (si preleva solo se la parte è presente); allo stesso modo l emissione ordine è una estensione della verifica giornaliera. L eliminazione di un ordine è inclusa nel reintegro. Figura 4: Diagramma dei casi d uso. 4.1 Ricerca e prelievo di una parte In Figura 5 viene mostrato il diagramma di sequenza corrispondente. Nel tracciare questo diagramma si è interposto tra l attore e il modello l oggetto della classe Cercatore, oggetto che svolge le funzione applicative di ricerca e prelievo di una parte. Nel sistema reale, tra questo oggetto e l attore sarà prevista un opportuna interfaccia che permetta di confezionare le chiamate ai metodi di Cercatore in base alle selezioni operate dall attore. Nello svolgimento del nostro esempio, ovviamente, si assume che l attore comunichi direttamente con l oggetto applicativo, fornendo ordinatamente come parametri: l auto (a), il complesso di alto livello (z) che sta subito sotto l auto nella gerarchia strutturale del modello, un complesso (y) che sta sotto al precedente, e la parte cercata (x), in modo che la ricerca possa effettuarsi attraversando la gerarchia. Naturalmente non è necessario che venga prelevata una parte elementare. Può essere prelevata una qualunque parte. In questo senso il diagramma di Figura 5 poteva essere stato tracciato in forma più generale assumendo che, escludendo l auto, tutti gli altri oggetti visitati fossero generiche parti. Il prelievo consiste semplicemente nell aggiornare la disponibilità della parte prelevata. Il diagramma di Figura 5 descrive solo lo scenario principale, quello che porta a trovare la parte cercata e a prelevarla. Gli scenari secondari corrispondono solo al fallimento della ricerca o alla conclusione corretta della ricerca di una parte che, però, non è disponibile. 4.2 Realizzazione di ricerca e prelievo di una parte I ragionamenti fin qui svolti e il diagramma di sequenza di Figura 5 permettono di ampliare il diagramma delle classi con l aggiunta dei metodi fin qui individuati (Figura 6). Ai fini dell esercizio il metodo cerca() deve prevedere come parametri l auto, il motore, il carburatore e la valvola a farfalla. Come già osservato in un sistema reale l interrogazione e la ricerca sarà presumibilmente 7

8 Figura 5: Ricerca e prelievo di una parte (scenario principale). Il diagramma presuppone che la ricerca venga effettuata fornendo come parametri: l auto, il complesso z, la sottoparte y del complesso e la parte elementare x (sottoparte di y). effettuata attraverso selezionando tramite interfaccia grafica parti e sottoparti secondo un ovvia successione che corrisponde alla struttura gerarchica del catalogo. public Parte cerca(string descrauto, String descrmot, String descrcarb, String descrparte){ if (catalogo.isempty()) { System.out.println("***Il catalogo è vuoto"); return null; Auto a = catalogo.getauto(descrauto); if (a == null) return null; Parte p = a.getparte(descrmot); if (p == null) return null; p = p.getparte(descrcarb); if (p == null) return null; p = p.getparte(descrparte); return p; Nello scrivere il metodo cerca() abbiamo assunto che i parametri siano le descrizioni (non gli ID) delle parti. Il metodo restituisce la parte cercata ovvero null se essa non viene trovata. Nel caso in cui la ricerca abbia esito favorevole il Main acquisisce la disponibilità della parte ricercata e preleva il numero di esemplari richiesto: Parte p = cercatore.cerca("panda1000", "motore Panda1000", "Carburatore aspirato", "Valvola a Farfa if (p!= null) { int disponib = p.getdispo(); if (disponib>k) p.preleva(k); //Prelevare k parti se ci sono 8

9 Figura 6: Diagramma delle classi con i metodi individuati per la popolazione del modello e per la ricerca e prelievo di una classe. 4.3 Verifica automatica di fine giornata La verifica di fine giornata con l eventuale emissione dell ordine sono avviate dall attore tempo tramite la classe applicativa GestoreOrdine. Questa presenta il metodo buildordine() avente la funzione di creare lo scheletro di un nuovo ordine e di riempire la lista con le parti da reintegrare. Il diagramma di sequenza relativo è in Figura 7. Come indicato in Figura 6, un ordine è essenzialmente costituito dalla lista delle parti da reintegrare, oltre che dalla data (e presumibilmente da un numero progressivo, non indicato in figura). La data la fornisce il sistema, il numero progressivo è fornito dall officina (che è ovviamente responsabile degli aspetti contabili, ecc.). Il riempimento della lista richiede la visita di tutte le parti del catalogo. Il metodo addreintegrande() passa come parametro la lista (in costruzione) delle parti da reintegrare: le parti che sono da reintegrare (cioè quelle che sotto la soglia e non sono già state ordinate) si aggiungono alla lista. Alla fine l ordine viene completato, con data e numero progressivo, e reso al chiamante. In Figura 8 viene riportata la parte del diagramma delle classi influenzata da quanto appena descritto. Nello sviluppare il programma, il metodo main() svolge la funzione del tempo. 4.4 Realizzazione della verifica automatica di fine giornata Qui di seguito riportiamo la classe GestoreOrdine. public GestoreOrdini(Catalogo catalogo, Officina officina){ this.catalogo = catalogo; this.officina = officina; 9

10 Figura 7: Verifica della disponibilità degli elementi a magazzino formazione dell ordine public Ordine buildordine(){ Ordine ordine = new Ordine(); ArrayList<Parte> listap = ordine.getlistap(); catalogo.addpartireintegrande(listap); if (listap.isempty()) return null; else { completaordine(ordine); return ordine; //lista vuota costruita da ordine private void completaordine(ordine o){ progressivo = progressivo+1; o.setprogressivo(progressivo); data = data +1; // TODO aggiustare data vera o.setdata(data); Qui di seguito mostriamo il modo in cui viene generato un ordine (nel Main). Il significato dei nomi è evidente. Ordine ordine = gestoreo.buildordine(); if (ordine!= null){ officina.addordine(ordine); officina.stampaordine(ordine); Il metodo completaordine(), provvede anche ad aggiungere l ordine all officina. 10

11 Figura 8: Aggiornamento del diagramma delle classi per effetto della funzionalità di verifica ed emissione ordini. 5 Considerazioni e miglioramenti Vengono fatti ora alcuni commenti al modello sviluppato. 1. Il nostro modello (Figura 1 e seguenti) tratta le auto come entità distinte rispetto alle parti. Ciò è dovuto al fatto che le auto non sono a magazzino ma solo a catalogo. Nel nostro sistema il magazzino comprende parti anche molto complesse come i motori. E più che naturale che il magazzino tenga solo un sottoinsieme degli oggetti che si trovano nel catalogo. Si possono seguire due strade: a) separare il catalogo dal magazzino; b) prevedere che ogni parte in catalogo abbia un attributo (amagazzino, di tipo booleano) che dice se la parte è anche a magazzino. Adottando la prima soluzione il catalogo serve a ricercare le parti, ottenendo il loro identificatore univoco (ID), tramite il quale è viene ricercata la parte nel magazzino. Il catalogo mantiene la sua struttura ad albero, mentre il magazzino diventa una struttura piatta in cui si ricerca in base all identificatore. La seconda soluzione evita la separazione del catalogo dal magazzino. L attributo dispo di Parte ha significato solo quando l attributo amagazzino è vero. IL nuovo modello è in Figura Un altra possibile miglioria consiste nel prevedere che le differenti parti a magazzino abbiano una soglia per la disponibilità diversa da parte a parte e che il reintegro possa essere fatto per quantità diverse a seconda delle parti (è presumibile che il differenziale di una Stilo abbia una soglia minima pari a 0, mentre il kit di pasticche per i freni potrebbe avere una soglia minima di alcune unità). 11

12 Figura 9: Modello che distingue le parti a magazzino da quelle solo a catalogo. 3. È già stato osservato che il metodo di costruzione degli ordini adottato è piuttosto rudimentale, in quanto presuppone la scansione di tutto il catalogo/magazzino per verificare se una data parte deve essere riordinata. Si può ricorrere al pattern Observer per segnalare quando una parte deve essere riordinata. Con riferimento al modello di Figura 8 possiamo fare di GestoreOrdine l oggetto osservatore al quale viene notificata la necessità di generare un ordine per una data parte, in modo che al termine della giornata GestoreOrdine abbia la lista delle parti da reintegrare e possa provvedere a generare l ordine. Intuitivamente viene da pensare che debba essere Parte a comunicare con GestoreOrdine (anche se Parte è una classe astratta e quindi dovrebbero essere gli oggetti delle classi Complesso e ParteElementare a segnalare il superamento della soglia). Il problema è che GestoreOrdine dovrebbe registrarsi su tutte le parti a magazzino. Ciò è manifestamente improponibile. Si può invece dare il ruolo di soggetto (osservato) a Cercatore, in quanto il metodo preleva() è perfettamente in grado di verificare se la parte prelevata è scesa sotto la soglia e avvisare GestoreOrdine. Nello scrivere il testo di GestoreOrdine bisogna prestare attenzione a come si gestisce la lista delle parti da riordinare. Nel programma allegato si sono seguiti questi criteri: viene tenuta una listaodierna in cui vengono inserite le parti sotto soglia, che non sono già state ordinate, ogni volta che arriva segnalazione da Cercatore. La segnalazione arriva solo al primo superamento della soglia: non accadrà mai che una parte venga segnalata due volte. Se per esempio la parte A arriva alla soglia, Cercatore lo segnale; se successivamente viene fatto un altro prelievo della parte A (ovviamente prima che venga reintegrata) che la porta a zero, Cercatore non lo segnala. al termine della giornata viene chiamato il metodo buildordine di GestoreOrdine. Esso costruisce l ordine allegandogli la lista e si dota di una nuova lista per le segnalazioni del giorno successivo. Data e numero progressivo vengono aggiunti dall officina 6 I programmi allegati Per convenienza di chi legge vengono allegate due versioni del programma. La prima, contenuta nella cartella src senzaobserver, si riferisce a quanto sviluppato fino al Paragrafo 5, la seconda, contenuta nella cartella src conobserver, contiene i miglioramenti di cui ai punti 1.b) e 3. 12

13 Chi avesse voglia di approfondire ulteriormente la materia consideri la possibilità di ricercare una parte in magazzino in base all ID, di prevedere diverse soglie per le parti, di prevedere diversi quantitativi di riordino, di prevedere che le parti contenute in un dato ordine possano arrivare in più tempi, ecc. Chiunque trovi errori, sia in questo documento sia nei programmi allegati, oppure faccia miglioramenti ai programmi è invitato a comunicarli a questo indirizzo: bucci@dsi.unifi.it 13