// Klassen und daraus gebildete Objektinstanzen
// unterstuetzen das Konzept der ABSTRAKTEN DATAENTYPEN (ADT)
// in hervorragender Weise.
//
// Ein ADT implementiert ein mathematisches Modell mit den
// darauf zulässigen Operationen, ohne die intern verwendete
// Modellstruktur sichtbar zu machen. Die interne Datenstruktur
// sowie die zur Implementierung der Methoden verwendeten 
// Algorithmen können daher verändert werden, ohne dass
// die verwendenden Programme zu modifizieren sind.
// Voraussetzung ist nur, dass die SCHNITTSTELLE der Operationen
// unverändert bleibt.
//
// Zwei ADTs sind äquivalent, wenn sie die selben Operationen
// anbieten und gleiche Aufruffolgen von Put-Funktionen zu identischen
// Rückgabewerten bei  Get-Aufruffolgen führen. Die Operationen duerfen
// sogar verschiedene Namen besitzen, wenn sie dieselben Schnittstellen
// implementieren und dieselbe Wirkung haben. (Bei der Verwendung muessen
// dann natuerlich die neuen Methodennamen eingesetzt werden.)
//
// Triviales Beispiel: wir ändern die Implementierung der Klasse
// MyContainer:

class MyContainer {

    // Diesmal nehmen wir 10 separate Variablen, um die
    // Objektattribute zu realisieren.

    int z0;
    int z1;
    int z2;
    int z3;
    int z4;
    int z5;
    int z6;
    int z7;
    int z8;
    int z9;

    // Alle Methoden werden neu implementiert,
    // da sich die internen Datenstrukturen verändert haben.
    // Die Schnittstellen bleiben unverändert.

    void put(int value, int atIndex) { 
	switch(atIndex) {
	    case 0: z0 = value; break;
	    case 1: z1 = value; break;
	    case 2: z2 = value; break;
	    case 3: z3 = value; break;
	    case 4: z4 = value; break;
	    case 5: z5 = value; break;
	    case 6: z6 = value; break;
	    case 7: z7 = value; break;
	    case 8: z8 = value; break;
	    case 9: z9 = value; break;
	}
    }


    int get(int atIndex) {
       switch(atIndex) {
	    case 0:  return z0;
	    case 1:  return z1;
	    case 2:  return z2;
	    case 3:  return z3;
	    case 4:  return z4;
	    case 5:  return z5;
	    case 6:  return z6;
	    case 7:  return z7;
	    case 8:  return z8;
	    case 9:  return z9;
	   default: System.out.println("falsche Index!"); return 0;
	}
    }

    int search(int theNumber) {

	if ( z0 == theNumber ) return 0;
	if ( z1 == theNumber ) return 1;
	if ( z2 == theNumber ) return 2;
	if ( z3 == theNumber ) return 3;
	if ( z4 == theNumber ) return 4;
	if ( z5 == theNumber ) return 5;
	if ( z6 == theNumber ) return 6;
	if ( z7 == theNumber ) return 7;
	if ( z8 == theNumber ) return 8;
	if ( z9 == theNumber ) return 9;

	return -1;

    }

    void copy(MyContainer fromContainer) {
	z0 = fromContainer.get(0);
	z1 = fromContainer.get(1);
	z2 = fromContainer.get(2);
	z3 = fromContainer.get(3);
	z4 = fromContainer.get(4);
	z5 = fromContainer.get(5);
	z6 = fromContainer.get(6);
	z7 = fromContainer.get(7);
	z8 = fromContainer.get(8);
	z9 = fromContainer.get(9);
    }

}

public class Oo2 {

    public static void main(String args[]) {

	int index;
        MyContainer o1 = new MyContainer();
        MyContainer o2 = new MyContainer();

	// Werte werden durch Auruf der
        // zugehoerigen Methoden in das Objekt geschrieben.
        // Die im Objekt verwendete Datenstruktur bleibt
        // fuer das verwendende Programm (also hier main())
        // unsichtbar.

        for (int iCnt=0; iCnt < 10; iCnt++) o1.put(10*iCnt,iCnt);

        // Algorithmen sind als METHODEN implementiert, die auf
        // den internen Zustandsdaten des Objektes operieren.
        // Damit muss die Datenstruktur nicht mehr
        // als Funktionsparameter angegeben werden.
        //
        // Die Methode wird auf dem zugehörigen Objekt aufgerufen.
        // Sprechweise: Das Objekt erhält die NACHRICHT (oder 
        // den BEFEHL), eine bestimmte Operation "auf sich selbst"
        // auszufuehren. Mit der Nachricht können Eingabeparameter
        // angegeben werden, welche die Befehlsausführung beeinflussen.

        o2.copy(o1);


	for (int iCnt=0; iCnt < 10; iCnt++)
	    System.out.println("b["+iCnt+"] = "+o2.get(iCnt));

        o2.put(7,5);

        index = o2.search(7);
        if ( 0 < index) System.out.println("b[] enthält 7 am Index " + index);

        index = o1.search(7);
        if ( 0 < index) 
            System.out.println("a[] enthält 7 am Index " + index);
        else
            System.out.println("a[] enthält keine 7");

    }

}
