Etterhvert som programmer vokser i størrelse, så er det naturlig å fordele koden på flere filer. Python kaller slike filer for moduler, og ved å bruke import-setninger kan én modul referere til og aktivere andre moduler. Java har en lignende mekanisme og også en import-setning, men forskjellene er vesentlige.

Python-moduler

Forskjellen har primært med hva det vil si å aktivere en modul. Ved bruk av import i Python, vil modulen det refereres til bli utført, med mindre den allerede er det. I vårt tilfelle er det rpncalc4ui som importerer rpncalc4core med setningen

import rpncalc4core

Resultatet er uansett at navnene i den importerte modulen er tilgjengelig, altså at notatarket tilsvarende modulen er opprettet. Det kan bare være ett slikt ark pr. modul, og det er derfor import-setningen bare kjører modulen hvis den ikke allerede er blitt utført. Når en siden ønsker å referere til funksjoner inni modulen, så bruker en modulnavnet og punktum som prefix foran funksjonsnavnet, f.eks.

if rpncalc4core.isOperand(token): 
	...

Java-klasser

Java sine moduler kalles klasser, og er lik moduler på den måten at de deklarerer variabler og funksjoner (kalles metoder i Java), og kjører metodene i kontekst av et notatark med variablene i. En viktig forskjell er imidlertid at en kan ha mange slik notatark med de samme variablene i (men selvsagt forskjellige verdier) og at alle disse må opprettes manuelt. Som regel vil en lagre referanser til disse, slik at en kan kalle metodene, omtrent på samme måte som en i Python kaller funksjoner i moduler.

Når rpncalc5ui-modulen i Python-koden over bruker rpncalc4core-navnet direkte, så må en i Java i stedet lage en instans av RPNCalc4Core-klassen og lagre denne i en variabel, for så å referere vha. denne:

RPNCalc4Core rpnCalc4Core = new RPNCalc4Core();
...
if (rpnCalc4Core.isOperand(token)) {
	...
}

Merk at det er ingen regel som sier at en må gi en variabel et navn som ligner på klassen, men det gjør koden lettere å lese.

En kan tegne dette som et objekt-diagram, som illustrerer hvordan RPNCalc4UI- og RPNCalc4Core-objektene henger sammen:

RPNCalc4UIRPNCalc4CoreList<Double> operands = ...rpnCalc4Core

Her er hele koden:

package python;

import java.util.ArrayList;
import java.util.List;

public class RPNCalc4Core {

    // deklarerer lista og setter den til en tom lista
    List<Double> operands = new ArrayList<Double>();

    boolean isOperand(String token) {
        // bruker samme teknikk som i Python:
        // kall konverteringsmetoden for String til desimaltall og returner true hvis det går
        try {
            Double.valueOf(token);
            return true;
        } catch (NumberFormatException nfe) {
            return false;
        }
    }

    List<Double> popOperands(int n) {
        if (operands.size() < n) {
            return null;
        }
        // må lage en ny liste, som fylles med de bakerste elementene i operands-lista
        List<Double> result = new ArrayList<Double>(n);
        while (n > 0) {
            // remove med angitt indeks fjerner og returnerer siste element
            double lastElement = operands.remove(operands.size() - 1);
            // elementet må legges først i lista, for å unngå å snu rekkefølgen
            result.add(0, lastElement);
            n = n - 1;
        }
        return result;
    }

    void plus() {
        // pop to operander, hvis mulig
        List<Double> ops = popOperands(2);
        // hvis det fantes to operander, så summeres de og push-es tilbake
        if (ops != null) {
            pushOperands(ops.get(0) + ops.get(1));
        }
    }

    void minus() {
        // pop to operander, hvis mulig
        List<Double> ops = popOperands(2);
        // hvis det fantes to operander, så beregnes differansen de og push-es tilbake
        if (ops != null) {
            pushOperands(ops.get(0) - ops.get(1));
        }
    }
    
    void printOperands() {
        System.out.println(operands);
    }

    void pushOperands(double operand) {
        // legg til bakerst
        operands.add(operand);
    }
}
package python;

import java.util.Scanner;

public class RPNCalc4UI {

    // oppretter en instans, som har en operands-liste inni seg
    RPNCalc4Core rpnCalc4Core = new RPNCalc4Core();

    void run() {
        // en Scanner hjelper oss å lese inn og tolke tekst
        // System.in dvs. konsollet, brukes som datakilde for Scanner-objektet
        Scanner scanner = new Scanner(System.in);
        while (true) {
            rpnCalc4Core.printOperands();
            System.out.print(" > ");
            String token = scanner.next();
            if (rpnCalc4Core.isOperand(token)) {
                double operand = Float.valueOf(token);
                rpnCalc4Core.pushOperands(operand);
            } else if (token.equals("exit")) {
                break;
            } else if (token.equals("+")) {
                rpnCalc4Core.plus();
            } else if (token.equals("-")) {
                rpnCalc4Core.minus();
            } else {
                System.out.println("Unsupported operator: " + token);
            }
        }
        // en Scanner må lukkes når vi er ferdig med den
        scanner.close();
        System.out.println("program exited");
    }

    // den obligatoriske oppstartsmetoden for programklasser
    public static void main(String[] args) {
        // vi lager en instans av program-klassen og lar den ta over
        new RPNCalc4UI().run();
    }
}
  • No labels