Datamatikeruddannelsen - Softwaredesign

Systemudvikling - tutorial 3

Endnu et eksempel på anvendelse af Larmans metode - hvad der skete i projektets 2. dag

I denne tutorial vil vi se endnu et eksempel på, hvordan anvisningerne fra tutorial 1 kan anvendes til løsning af en konkret opgave fra use case til færdig programkode skrevet i C#. Opgaven består i at udvikle et virksomhedsspil - beskrivelsen af hele opgaven kan ses her.

Ligesom på første dag starter man på projektets anden dag med at vælge nogle passende use cases, som man kan fortsætte med at realisere. I denne situation har jeg valgt at fortsætte med den use-case, der i opgavebeskrivelsen følger umiddelbart efter de to, der blev udviklet på den første dag. Den pågældende use-case hedder Opdater produktion. Denne use-case kræver kun en enkelt systemoperation for at kunne blive udført - i praksis udløses operationen ved at brugeren trykker på en knap på skærmbilledet.

System Sekvens Diagram

Nedenfor er vist system sekvens diagrammet efter tilføjelse af den nye operation:

Sekvensdiagram for systemoperationen "opdaterProduktion"

Denne systemoperation er udledt af use casen Opdater produktion. I dette tilfælde har jeg valgt at starte med udviklingen af sekvensdiagrammet før domænemodellen bliver opdateret med de nyfundne klasser.

Som det fremgår af diagrammet har jeg tænkt mig at tilføje den nye operation til den eksisterende Facadecontroller. I forbindelse med designet af løsningen er man nødt til at overveje struktureringen af de objekter, der skal indeholde data vedrørende produktionen. Her bør man inddrage Larmans overvejelser om brug af GRASP mønstre (kap. 17).

Jeg forestiller mig her en struktur, som lægger sig tæt op ad den struktur, der beskrives i spillet: Virksomhedens produktion kan foregå i 1 til 3 fabrikker, hver fabrik består af et antal mulige værksteder (mellem 1 og 4), i hvert værksted kan der foregå en produktion i forskellig hastighed.

Færdiggørelsen af et produkt sker i løbet af et antal kvartaler, så jeg forestiller mig, at opdateringen kan ske i to tempi: I første omgang opdateres en attribut med det aktuelle produktionstrin ved at addere én til. I næste omgang undersøges det, hvor mange færdige produkter, der herefter er blevet produceret, og disse færdige produkter tilføjes til færdigvarelageret.

Domænemodel

Domænemodellen fra dag 1 udvides med de klasser og attributter, som overvejelserne i forbindelse med tegningen af sekvensdiagrammet har givet anledning til. Den modificerede domænemodel er gengivet nedenfor:

Kodning

Først kodes ændringerne i domænemodellen.

Lager klassen
class Lager
{
private int antalMaster;
private int valueMaster;
  public Lager()
  {
    antalMaster = 0;
    valueMaster = 0;
  }
  public void modtagMaster()
  {
    Master++;
    Value = Value + 2;
  }
  public int Master
  {
    get { return antalMaster; }
    set { antalMaster = value; }
  }
  public int Value
  {
    get { return valueMaster; }
    set { valueMaster = value; }
  }
}
Vaerksted klassen
class Vaerksted
{
private string type;
private string produkt;
private int step;
  public Vaerksted()
  {
    type = "";
    produkt = "";
    step = 0;
  }
  public Vaerksted(string enType, string etProdukt)
  {
    type = enType;
    produkt = etProdukt;
    step = 0;
  }
  public string Type
  {
    get { return type; }
    set { type = value; }
  }
  public string Produkt
  {
    get { return produkt; }
    set { produkt = value; }
  }
  public int Step
  {
    get { return step; }
    set { step = value; }
  }
  public void opdater()
  {
    if (step > 0)
    step++;
  }
  public int faerdig(string etProdukt)
  {
    int antal = 0;
    if (Produkt == etProdukt)
      if (Type == "Funktionsværksted")
        if (Step == 4)
        {
          antal = 1;
          Step = 0;
        }
    if (Produkt == etProdukt)
      if (Type == "Produktværksted")
        if (Step == 3)
        {
          antal = 1;
          Step = 0;
        }
    return antal;
  }
}
Fabrik klassen
class Fabrik
{
private string navn;
private int vaerdi;
private Vaerksted[] v;
  public Fabrik(string etNavn, int antal, int enVaerdi)
  {
    navn = etNavn;
    vaerdi = enVaerdi;
    v = new Vaerksted[antal];
  }
  public void buyVaerksted(int i, Vaerksted vs)
  {
    v[i] = vs;
  }
  public void opdater()
  {
    for (int i = 0; i < v.Length; i++)
    {
      v[i].opdater();
    }
  }
  public int faerdig(string etProdukt)
  {
    int antal = 0;
    for (int i = 0; i < v.Length; i++)
    {
      antal = antal + v[i].faerdig(etProdukt);
    }
    return antal;
  }
  public int Vaerdi
  {
    get { return vaerdi; }
    set { vaerdi = value; }
  }
  public int getAntal()
  { 
    return v.Length; 
  }
  public Vaerksted getVaerksted(int position)
  {
    return v[position];
  }
Produktion klassen
class Produktion
{
  private Fabrik[] f = new Fabrik[3];
  public Produktion()
  {
    Fabrik fabrik;
    fabrik = new Fabrik("Den Gamle Fabrik", 4, 20);
    Vaerksted vs;
    vs = new Vaerksted("Funktionsværksted", "Master");
    vs.Step = 1;
    fabrik.buyVaerksted(0, vs);
    vs = new Vaerksted("Funktionsværksted", "Master");
    vs.Step = 2;
    fabrik.buyVaerksted(1, vs);
    vs = new Vaerksted("Funktionsværksted", "Master");
    vs.Step = 3;
    fabrik.buyVaerksted(2, vs);
    vs = new Vaerksted("Produktværksted", "Master");
    vs.Step = 1;
    fabrik.buyVaerksted(3, vs);
    f[0] = fabrik;
    fabrik = new Fabrik("Den Lille Fabrik", 0, 0);
    f[1] = fabrik;
    fabrik = new Fabrik("Den Nye Fabrik", 0, 0);
    f[2] = fabrik;
  }
  public Fabrik getFabrik(int index)
  {
    return f[index];
  }
  public void opdater()
  {
    for (int i = 0; i < 3; i++)
    {
      if (f[i].getAntal() > 0) f[i].opdater();
    }
  }
  public int faerdig(string etProdukt)
  {
    int antal = 0;
    for (int i = 0; i < 3; i++)
    {
      if (f[i].getAntal() > 0) antal = antal + f[i].faerdig(etProdukt);
    }
    return antal;
  }
}

Dernæst tilføjes koden for den nye use-case til facade controller klassen. Opbygningen af denne kode følger det tidligere viste sekvensdiagram.

Facade controlleren
class Facade
{
  ...


  public void opdaterProduktion()
{
Produktion p = m.getProduktion();
Lager l = m.getLager();
int master = 0;
Fabrik f;
f = p.getFabrik(0);
f.opdater();
master = master + f.faerdig("Master");
f = p.getFabrik(1);
f.opdater();
master = master + f.faerdig("Master");
f = p.getFabrik(2);
f.opdater();
master = master + f.faerdig("Master");
l.Master = l.Master + master;
}
}
Next step knappens eventhandler

Endelig opdateres koden for brugergrænsefladens Next step knap, så den kan håndtere funktionaliteten for den netop tilføjede use case.

private void buttonStep_Click(object sender, EventArgs e)
{
  ...


  switch (state)
  {
    ...
    case 5:
{
f.opdaterProduktion();
UpdateGUI();
if (textProduktion1Step.Text == "0" & textProduktion1Type.Text != "")
textProduktion1Step.ReadOnly = false;
if (textProduktion2Step.Text == "0" & textProduktion2Type.Text != "")
textProduktion2Step.ReadOnly = false;
if (textProduktion3Step.Text == "0" & textProduktion3Type.Text != "")
textProduktion3Step.ReadOnly = false;
if (textProduktion4Step.Text == "0" & textProduktion4Type.Text != "")
textProduktion4Step.ReadOnly = false;
textNextStep.Text = "Modtag bestilte varer";
break;
} ...
} }

Et Visual Studio projekt med koden fra de første 2 iterationer kan downloades her.


Oprettet: 12. december 2007
Sidst opdateret: 9. januar 2008