RandomMinMaksSnitt-eksemplet er et kode-eksempel som viser bruk av hovedprogram for å bruke/teste flere andre (små)klasser.

Dette eksemplet er ment å illustrere to ting:

  1. Hvordan oppgavene til et komplekst objekt kan deles opp og fordeles over flere objekter.
  2. Hvordan et hovedprogram, kodet i en hovedprogramklasse, kan brukes for å koordinere og prøve ut andre klasser.

Anta at du skal prøve ut en metode for å lage tilfeldige tall, f.eks. basert på http://en.wikipedia.org/wiki/Random_number_generation. I første omgang ønsker du å lage 1000 tilfeldige tall og sjekke minimum-, maksimum og gjennomsnittsverdien. Her er en hovedprogramklasse som inneholder algoritmen fra Wikipedia og som beregner de tre nevnte verdiene.

// fra http://en.wikipedia.org/wiki/Random_number_generation
public class RandomProgram1 {

    // tilstand for tilfeldig tall-generatoren
    long mw = 31;
    long mz = 42;
     
    long nextRandom() {
        mz = 36969 * (mz & 65535) + (mz >> 16);
        mw = 18000 * (mw & 65535) + (mw >> 16);
        return (mz << 16) + mw;
    }

	void init() {
    }
    
    // tilstand for minimum
    long min = Long.MAX_VALUE;
    // tilstand for maksimum
    long max = Long.MIN_VALUE;
    // tilstand for gjennomsnitt
    int count = 0;
    long sum = 0;
    
    void run() {
        while (count < 1000) {
            long randomValue = nextRandom();
            if (randomValue < min) {
                min = randomValue;
            }
            if (randomValue > max) {
                max = randomValue;
            }
            sum += randomValue;
            count++;
        }
        System.out.println("Min: " + min);
        System.out.println("Max: " + max);
        System.out.println("Average: " + (sum / count));
    }
    
    public static void main(String[] args) {
        RandomProgram1 program = new RandomProgram1();
        program.init();
        program.run();
    }
}

De to første long-attributtene m_w og m_z er tilstand knyttet til tilfeldige tall-generatoren. For hvert nye tilfeldige tall som beregnes av nextRandom()-metoden, så oppdateres disse to attributtene.

min- og max-attributtene holder henholdsvis hittil minste og hittil største verdi, og initialiseres til henholdsvis den største og minste mulige long-verdiene i Java.

count- og sum-attributtene brukes for å beregne gjennomsnittet.

init()-metoden er tom, siden den gjerne brukes til å konfigurere objekt(struktur)er og vi her ikke har noen objekter (bortsett fra hovedprogram-objektet).

run()-metoden inneholder en løkke som går 1000 ganger. For hver runde så lager den et nytt tilfeldig tall med nextRandom()-metoden og oppdaterer min-, max-, sum- og count-attributtene. min oppdateres hvis den nye verdien er mindre, max oppdateres hvis den nye verdien er større og sum og count oppdateres alltid.

Et objekttilstandsdiagram for klassen vil se slik ut:

RandomProgram1// tilstand for generatormw = 31mz = 42// tilstand for minimummin = 9223372036854775807// tilstand for maksimummax = -9223372036854775808// tilstand for gjennomsnittcount = 0sum = 0RandomProgram1// tilstand for generatormw = 558000mz = 1552698// tilstand for minimummin = 101758174128// tilstand for maksimummax = 101758174128// tilstand for gjennomsnittcount = 1sum = 101758174128RandomProgram1// tilstand for generatormw = 606816008mz = 1677283553// tilstand for minimummin = 101758174128// tilstand for maksimummax = 109923061745416// tilstand for gjennomsnittcount = 2sum = 110024819919544RandomProgram1// tilstand for generatormw = 290483840mz = 1240974898// tilstand for minimummin = 3057780577// tilstand for maksimummax = 158694648374228// tilstand for gjennomsnittcount = 1000sum = 78963637600257262runde 1runde 2... runde 1000

Ulempene med denne klassen er flere, bl.a.

  • Klassen har mange oppgaver å utføre og attributter å holde rede på.
  • Det er vanskelig å holde rede på hvilke attributter som brukes til hvilket formål.
  • count-attributter brukes til to formål: å holde rede på antall runder i løkka og hjelpe til å beregne gjennomsnitt
  • Dersom en vil undersøke andre egenskaper til tilfeldig tall-generatoren så blir det mer og mer forvirrende

En ryddigere løsning er å dele problemet opp i mindre deler og la én klasse ta seg av hver del. Dette er grunnprinsippet i objektorientering: En klasse skal ha (kun) ett formål!

Her er det naturlig å ha én klasse for tilfeldig tall-generatoren, én for å holde rede på minimumsverdien, én for å holde rede på maksimumsverdien og én for å håndtere gjennomsnittberegningen. Siden hver av disse kun har ett formål og gjør én ting, så er det enkle å skrive. Hovedprogramklassen får en koordinerende rolle og blir også enklere å skrive.

public class RandomProgram2 {
    Random random;
    Min min;
    Max max;
    Average average;
    
    void init() {
        random = new Random();
        min = new Min();
        max = new Max();
        average = new Average();
    }
    
    void run() {
        for (int i = 0; i < 1000; i++) {
            long randomValue = random.nextRandom();
            min.accumulate(randomValue);
            max.accumulate(randomValue);
            average.accumulate(randomValue);
        }
        System.out.println("Min: " + min.getMin());
        System.out.println("Max: " + max.getMax());
        System.out.println("Average: " + average.getAverage());
    }
    
    public static void main(String[] args) {
        RandomProgram2 program = new RandomProgram2();
        program.init();
        program.run();
    }
}

Objekttilstandsdiagrammet for klassen vil se slik ut:

RandomProgram2Randommw = 31mz = 42Minmin = 9223372036854775807Maxmax = -9223372036854775808Averagecount = 0sum = 0RandomProgram2Randommw = 558000mz = 1552698Minmin = 101758174128Maxmax = 101758174128Averagecount = 1sum = 101758174128RandomProgram2Randommw = 606816008mz = 1677283553Minmin = 101758174128Maxmax = 109923061745416Averagecount = 2sum = 110024819919544RandomProgram2Randommw = 290483840mz = 1240974898Minmin = 3057780577Maxmax = 158694648374228Averagecount = 1000sum = 78963637600257262randomminmaxaveragerandomminmaxaveragerunde 1randomminmaxaveragerunde 2randomminmaxaverage... runde 1000

Programmet har i praksis samme totaltilstand som i den første varianten, men tilstanden er fordelt over flere objekter. Istedenfor ett komplekst objekt, så har en fem mindre komplekse objekter.

Selv om gevinsten ikke er så stor for et så lite system, så er tilsvarende opprydding helt essensielt for å håndtere kompleksiteten til store systemer.

public class Random {

    // from http://en.wikipedia.org/wiki/Random_number_generation

    long mw = 31;
    long mz = 42;
     
    long nextRandom() {
        mz = 36969 * (mz & 65535) + (mz >> 16);
        mw = 18000 * (mw & 65535) + (mw >> 16);
        return (mz << 16) + mw;
    }
}
public class Min {
    long min = Long.MAX_VALUE;
    
    public long getMin() {
        return min;
    }
    
    void accumulate(long value) {
        if (value < min) {
            min = value;
        }
    }
}
public class Max {
    long max = Long.MIN_VALUE;
    
    public long getMax() {
        return max;
    }
    
    void accumulate(long value) {
        if (value > max) {
            max = value;
        }
    }
}
public class Average {
    long count = 0, sum = 0;
    
    long getAverage() {
		if (count == 0) {
			return 0;
		}
        return sum / count;
    }
    
    void accumulate(long value) {
        sum += value;
        count++;
    }
}