Dialogdesign med Java Swing – del 3

Vidare kan vi av skissen se att dialogens komponenter har det gemensamt att de behöver tillgång till varsin modell som utgörs av en lista av värdeobjekt.

Här är det lätt att göra misstaget att designa dialogens modell direkt utifrån komponenternas behov, genom att skapa tre listor. Låt bli det. Det leder till kod som blir både svårare att utöka på sikt och jobbigare att få en överblick över.

Gör hellre en analys utifrån helheten – det vi kan kalla dialogens datamodell. Dialogen som helhet ska kunna hantera alla valbara och valda element och kan hålla isär dem med deras unika id (kombinationen _id och _kalla i TidsintervallVo).

Det enda vi skulle behöva lägga till är en wrapper för att dessutom kunna hålla reda på om ett visst element är valt eller inte. Vi använder en wrapper när vi behöver lägga till mer attribut och metoder runt ett värdeobjekt som för egen del bara ska vara ett dataöverföringsobjekt utan logik.

package com.golcher.tidsintervall.komponenter.data;

public class TidsintervallWrapper
{
    private final TidsintervallNyckel _nyckel; // Immutable key att använda i HashMap
    private TidsintervallVo _varde;
    private boolean _arVald;

    public TidsintervallWrapper(TidsintervallVo vo)
    {
        _nyckel = new TidsintervallNyckel(vo);
        _varde = vo;
        _arVald = false;
    }

    public void sattStatus(boolean arVald)
    {
        _arVald = arVald;
    }

    public TidsintervallNyckel nyckel()
    {
        return _nyckel;
    }

    public TidsintervallVo varde()
    {
        return _varde;
    }

    public boolean arVald()
    {
        return _arVald;
    }

    @Override
    public String toString()
    {
        return _varde.toString();
    }

    public void sattVarde(TidsintervallVo vo)
    {
        _varde = vo;
    }
}

När vi har lagt till en sådan wrapper kan vi hantera modellen som en HashMap och sedan enkelt avgöra vilken komponent som ska ha ett visst element med en enkel regel – är elementet valt ska det visas med övriga valda oavsett källan, annars ska det visas i den komponent som utger sig för att vara för element av den källan.

För att kunna hantera element i en HashMap korrekt krävs en immutable (oföränderlig) nyckel. Vi vet redan att vi ska bygga vår av respektive elements ID och dess källa, men för att säkerställa att ingen missar hur det ska göras, bryter vi ut det till en egen klass istället för att använda String som nyckel. På det tämligen enkla sättet slipper vi att senare leta efter buggar orsakade av att olika utvecklare råkat t ex kasta om ordningen på fälten som ingår eller har hanterat dem på olika sätt avseende stora/små bokstäver. Att bygga bort problemen i förväg tar väldigt lite tid, men sparar massor!

package com.golcher.tidsintervall.komponenter.data;

public class TidsintervallNyckel
{
    private final String _nyckel; // Immutable key (id + kalla) i HashMap
    public TidsintervallNyckel(TidsintervallVo vo)
    {
        _nyckel = vo.getId() + "-" + vo.getKalla().toString();
    }

    @Override
    public String toString()
    {
        return _nyckel;
    }
}

I nästa avsnitt ska vi kika mer i detalj på dialogmodellen. Vi ses där.