Ein Merkmal der objektorientierten Programmierung ( OOP ) ist, dass die Begriffe, die das Problem beschreiben, dieselben sind, die im Programm verwendet werden.
In Java sind es die Interfaces, durch die Begriffe einer Sprache erzeugt werden. Durch das Implementieren der Interfaces werden die Begriffe dann definiert.
In jedem Programm gibt es Klassen, die selbst keine Interfaces implementieren, sondern Objekte weiterverarbeiten, die Interfaces implementieren. Dieses Zusammenspiel begründet die Allgemeingültigkeit der Interfaces.
Im folgenden Beitrag wird die Beschreibung einer einfachen elektrischen Schaltung in ein Java-Programm umgesetzt. Das Java-Programm leistet neben dem eigentlichen Nachbilden der Schaltung und ihrer Funktionalität noch die Ausgabe auf der Konsole. Die folgenden Ausführungen konzentrieren sich auf den ersten Aspekt. Die Programmteile, die sich auf die Ausgabe beziehen werden ebenso weggelassen wie Konstruktoren usw. Die Auslassungen sind durch //... gekennzeichnet. Das komplette Programm mitsamt Ausgabe-Funktionalität mittels überschriebener toString()-Methoden findet man am Schluss dieses Beitrags.
Es geht hier um folgende Gesichtspunkte:

Die Schaltung besteht aus:
Soweit die Beschreibung. Das Programm selbst soll im Wesentlichen die eben festgelegten Begriffe verwenden. Hier folgt ein Ausschnitt aus dem Hauptprogramm:
public static void main( String [] args )
{
Batterie batterie1 = new Batterie( "Batterie1");
Draht draht1 = new Draht( "Draht1" );
Schalter schalter1 = new Schalter( "Schalter1" );
Draht draht2 = new Draht( "Draht2" );
Gluehbirne gluehbirne1 = new Gluehbirne( "Gluehbirne1" );
//...
draht1.verbinden( batterie1, schalter1 );
draht2.verbinden( schalter1, gluehbirne1 );
//...
batterie1.laden();
//...
schalter1.schalten();
//...
}
Wenn man bei diesem Programm-Ausschnitt in die Leerzeilen geeignete System.out.println-Zeilen einsetzt ( siehe das komplette Programm), kann man zur Kontrolle den Zustand der Bauteile im Programmverlauf anzeigen und erhält folgende Ausgabe:
[ Batterie Batterie1 leer ] [ Schalter Schalter1 aus : ? --> ? ] [ Birne Gluehbirne1 leuchtet nicht] [ Draht Draht1 : ? --> ? ] [ Draht Draht2 : ? --> ? ] [ Draht Draht1 : Batterie1 --> Schalter1 ] [ Draht Draht2 : Schalter1 --> Gluehbirne1 ] [ Batterie Batterie1 leer ] [ Schalter Schalter1 aus : Batterie1 --> Gluehbirne1 ] [ Birne Gluehbirne1 leuchtet nicht] [ Batterie Batterie1 voll ] [ Birne Gluehbirne1 leuchtet nicht] [ Schalter Schalter1 ein : Batterie1 --> Gluehbirne1 ] [ Birne Gluehbirne1 leuchtet]Mit denselben sprachlichen Mitteln ist es möglich, eine Glühbirne mit einem Draht direkt an eine Batterie anzuschliessen, oder zwischen Batterie und Glühbirne mehrere Schalter in Serie zu schalten. Parallelschaltungen sind nicht möglich.
Die Interfaces bilden diese Begriffe im Programm ab. Auf einer gewissen Ebene der og. elektrischen Schaltung beschreibt man erst einmal, dass gewisse Bauteile miteinander verbunden werden, ohne zu sagen, wie das geschieht. Ausserdem kann man sagen, bestimmte Bauteile sind Stromquellen ( Batterie ), andere sind Stromverbraucher ( Gluehbirne ), und Schalter sind beides: Schalter nehmen Strom auf und geben ihn weiter.
An dieser Stelle wird deutlich: Ein Experte des btr. Fachgebietes müsste diese Begriffsbildung leisten. Es geht hier um inhaltliche Fragen. Trotzdem: Aus der Sicht der Java-Programmierung stellt sich die Situation folgendermassen dar:
interface Bauteil
{
public boolean hatStrom();
public void setStrom( boolean s );
public String getBezeichnung();
}
Jedes Bauteil ist ausserdem durch die Eigenschaft gekennzeichnet, Konsument und/oder Lieferant von Strom zu sein. Bei der Verdrahtung von Bauteilen sollen die Bauteile selbst die Information speichern, mit welchen anderen Bauteilen sie verdrahtet sind: die Lieferanten merken sich, welche anderen Bauteile ihre Konsumenten sind; die Konsumenten merken sich ihre Lieferanten. Daraus ergeben sich zwei weitere Interfaces, die beide Ableitungen des Interface Bauteil sind.
interface Konsument extends Bauteil
{
public void setLieferant( Lieferant e );
}
interface Lieferant extends Bauteil
{
public void setKonsument( Konsument e );
}
Die Interfaces stellen sich in der Darstellung als UML-Diagramm folgendermassen dar:
Der Klasse Draht ist es egal, welche Bauteile sie miteinander verbindet, allerdings soll immer ein Lieferant mit einem Konsumenten verbunden werden. Die Klasse Draht stellt einfach Verbindungen her, ohne sich um Details zu kümmern. Es ist dies der typische Fall, dass die Methoden einer Klasse, die selbst kein Interface implementiert, als Parameterdatentypen Objekte von Klassen verlangen, die Interfaces implementerien.
class Draht
{
//...
public void verbinden( Lieferant s, Konsument v )
{
//...
s.setKonsument( v );
v.setLieferant( s );
}
//...
}
Der Lieferant bekommt also gesagt, mit welchem Konsument er verbunden wird und muss sich selbst um die Weiterverarbeitung dieser Information kümmern. Für den Konsument gilt entsprechendes. Die Klasse Draht verlässt sich hier darauf, dass Lieferant und Konsument die passenden Methoden besitzten. Die Parameter-Datentypen stellen hier sicher, dass nur Lieferanten mit Konsumenten in der korrekten Art miteinander verbunden werden können: nur Objekte, deren Klassen die beiden Interfaces implementieren, werden miteinander verbunden.
Beim Verbinden durch einen Draht wird hier die Methode setLieferant( parameter ) aufgerufen: die Gluehbirne merkt sich, wer ihr StromLieferant ist, indem sie ihre private Eigenschaft StromLieferant auf den Wert des Parameters setzt. Das ist alles.
Die wichtigste Methode ist hier hatStrom(): eine Gluehbirne hat dann Strom, wenn sie einen StromLieferanten hat und der StromLieferant Strom hat. Dabei ist es egal, was für einer Klasse der Lieferant genau angehört: eine Gluehbirne kann mittels Draht an einem Schalter dranhängen oder direkt an einer Batterie.
Die hier ausgelassen Programmteile betreffen die Ausgabe, siehe das komplette Programm der Klasse Gluehbirne.
class Gluehbirne implements Konsument
{
//...
private Lieferant StromLieferant;
private boolean hatStrom;
//...
public void setLieferant( Lieferant e )
{
StromLieferant = e;
}
public void setStrom( boolean s )
{
hatStrom = s;
}
public boolean hatStrom()
{
if( StromLieferant != null )
setStrom( StromLieferant.hatStrom());
return hatStrom;
}
//...
}
laden(), mit der die Eigenschaft hatstrom festgelegt wird.
Die hier ausgelassen Programmteile betreffen die Ausgabe, siehe das komplette Programm der Klasse Batterie.
class Batterie implements Lieferant
{
//...
private boolean hatStrom;
private Konsument StromKonsument;
//...
public void setKonsument( Konsument e )
{
StromKonsument = e;
}
public boolean hatStrom()
{
return hatStrom;
}
public void setStrom( boolean lad )
{
hatStrom = lad;
}
public void laden()
{
hatStrom = true;
}
//...
}
Da Schalter Lieferanten und Konsumenten haben, gibt es beide Methoden setLieferant() und setKonsument().
Die Zeile
private Bauteil StromLieferant, StromKonsument;in der 4ten Zeile des folgenden Programmausschnitts macht sich das sog. Upcasting zunutze. Alternativ hätte man 2 Zeilen schreiben können:
private Lieferant StromLieferant; private Konsument StromKonsument;Da die Interfaces Lieferant und Konsument Ableitungen des Interface Bauteil sind, kann man sie selbst auch als Interfaces vom Typ Bauteil behandeln.
Die Methode schalten() schaltet zwischen ein und aus hin und her.
Der Schalter hat dann Strom (boolean hatStrom), wenn er einen Lieferanten hat, wenn der Lieferant Strom hat und der Schalter selbst eingeschaltet ist.
Methoden für Ausgabe siehe das komplette Programm der Klasse Schalter.
class Schalter implements Konsument, Lieferant
{
//...
private Bauteil StromLieferant, StromKonsument;
private boolean hatStrom;
private boolean ein;
//...
public void setLieferant( Lieferant e )
{
StromLieferant = e;
}
public void setKonsument( Konsument e )
{
StromKonsument = e;
}
public boolean getEin ()
{
return ein;
}
public void setEin( boolean ea )
{
ein = ea;
}
public void setStrom( boolean s )
{
hatStrom = s;
}
public boolean hatStrom()
{
if( Lieferant != null )
return ( StromLieferant.hatStrom() == true && ein == true );
else return false;
}
public void schalten()
{
if( ein == false){
if( StromLieferant.hatStrom() == true )
StromKonsument.setStrom( true );
ein = true;
}
else if( ein == true ){
if( StromKonsument.hatStrom() == true )
StromKonsument.setStrom( false );
ein = false;
}
}
//...
}
hatStrom() der Bauteile regelt die Kommunikation zwischen verbundenen Bauteilen, indem sie jeweils bei den Lieferanten nachsieht, ob die ihrerseits Strom haben.
In unserem Beispiel könnte als neue Anforderung die Frage nach Parallelschaltungen gestellt werden. Eigentlich einfach:
// Der komplette Programm-Text mit javadoc-Kommentaren
//
//
// Das Hauptprogramm enthaelt 4 verschiedene Schaltungen:
// 1.: Batterie -> Schalter2 -> Schalter1 -> Birne
// 2.: Batterie -> Schalter -> Birne
// 3.: Batterie -> Birne
// 4.: wie 2
//
// copyright März 2001 www.AndreasGoedel.de
package schalt;
/**
* elektrisches Bauteil.
* Hat Strom oder nicht
* und Strom kann ein-ausgeschaltet werden.
* Jedes Bauteil hat Bezeichnung
*/
interface Bauteil
{
/**
* Strom drauf oder nicht
*/
public boolean hatStrom();
/**
* ein- ausschalten
*/
public void setStrom( boolean s );
/**
* zur Verwendung durch die toString()-Methoden anderer Klassen
*/
public String getBezeichnung();
}
/**
* Elektrische Bauteile, die Strom aufnehmenen.
* Jeder Konsument ist mit Lieferanten verbunden.
*/
interface Konsument extends Bauteil
{
/**
* Lieferant festlegen.
*/
public void setLieferant( Lieferant e );
}
/**
* Elektrische Bauteile, die Strom liefern.
* Jeder Lieferant ist mit konsumenten verbunden.
*/
interface Lieferant extends Bauteil
{
/**
* Konsument festlegen.
*/
public void setKonsument( Konsument e );
}
/**
* Gluehbirne ist Konsument
*/
class Gluehbirne implements Konsument
{
private String Bezeichnung;
private Bauteil StromLieferant;
private boolean hatStrom;
/**
*@param Bezeichnung ein Name für das Objekt Gluehbirne
*/
public Gluehbirne( String Bezeichnung )
{
this.Bezeichnung = Bezeichnung;
}
/**
* wird aufgerufen, wenn Verbindung hergestellt wird
* @see Draht
*/
public void setLieferant( Lieferant e )
{
StromLieferant = e;
}
/**
* Strom auf die Gluehbirne geben
*/
public void setStrom( boolean s )
{
hatStrom = s;
}
/**
* die Gluehbirne hat dann Strom, wenn ein Lieferant verbunden ist
* und der Lieferant Strom hat
*/
public boolean hatStrom()
{
if( StromLieferant != null )
setStrom( StromLieferant.hatStrom());
return hatStrom;
}
/**
* Bezeichnung zur Verwendung durch die toString()-Methoden
*/
public String getBezeichnung()
{
return Bezeichnung;
}
/**
* Ausgabe von Bezeichnung, und "leuchtet", falls hatStrom()
*/
public String toString()
{
return "[ Birne " +
Bezeichnung + " "
+( hatStrom() == true ? " leuchtet" : " leuchtet nicht")
+ "] ";
}
}
/**
* Verbindet Bauteile miteinander, und zwar Lieferant mit Konsument.
*
* Die Bezugnahme auf die privaten Variablen Bezeichnung, Stromquelle, Verbraucher
* dient hier ausschliesslich der Ausgabe für die toString()-Methode.
* Diese Methode erbt jede Klasse von der Klasse java.lang.Object, siehe Handbuch.
* Sie wird hier also überschrieben.
* Der Aufruf von System.out.println( draht1 ) bringt
* [ Draht Draht1 : Batterie1 --> Schalter1 ]
*
*/
class Draht
{
private String Bezeichnung;
private Bauteil Stromquelle;
private Bauteil Verbraucher;
/**
*@param Bezeichnung ein Name für das Objekt Draht
*/
public Draht( String Bezeichnung )
{
this.Bezeichnung = Bezeichnung;
}
/**
* Beim Erzeugen des Draht-Objekts Lieferanten und Konsumenten übergeben.
* Damit spart man das Verbinden.
* @param Bezeichnung ein Name für das Objekt Draht
* @param L Lieferant
* @param K Konsument
*/
public Draht( String Bezeichnung, Lieferant L, Konsument K )
{
this.Bezeichnung = Bezeichnung;
this.verbinden( L, K );
}
/**
* Verbindet Lieferant mit Konsument und ruft deren Verbindungsmethoden:
* jedes Bauteil weiss, mit wem es verbunden ist
* @see Konsument
* @see Lieferant
*/
public void verbinden( Lieferant s, Konsument v )
{
Stromquelle = s;
Verbraucher = v;
s.setKonsument( v );
v.setLieferant( s );
}
/**
* Ausgabe von Bezeichnung und den Bauteilen, die verbunden werden
*/
public String toString()
{
String LiefBez = "?";
String KonsBez = "?";
if( Stromquelle != null )
LiefBez = Stromquelle.getBezeichnung();
if( Verbraucher != null )
KonsBez = Verbraucher.getBezeichnung();
return "[ Draht " +
Bezeichnung + " : "
+ LiefBez + " --> "
+ KonsBez + " ]";
}
}
/**
* Schalter sind Lieferanten und Konsumenten zugleich
*/
class Schalter implements Konsument, Lieferant
{
private String Bezeichnung;
private Bauteil StromLieferant, StromKonsument;
private boolean hatStrom;
private boolean ein;
/**
*@param Bezeichnung ein Name für das Objekt Schalter
*/
public Schalter( String Bezeichnung )
{
this.Bezeichnung = Bezeichnung;
}
/**
* wird aufgerufen, wenn Verbindung hergestellt wird
* @see Draht
*/
public void setLieferant( Lieferant e )
{
StromLieferant = e;
}
/**
* wird aufgerufen, wenn Verbindung hergestellt wird
* @see Draht
*/
public void setKonsument( Konsument e )
{
StromKonsument = e;
}
/**
* der Schalter ist ein oder aus
*/
public boolean getEin ()
{
return ein;
}
/**
* der Schalter wird geschaltet
*/
public void setEin( boolean ea )
{
ein = ea;
}
public void setStrom( boolean s )
{
hatStrom = s;
}
/**
* der Schalter hat Strom, wenn er an einen Lieferanten angeschlossen ist,
* wenn sein Lieferant Strom hat,
* und wenn der Schalter selbst eingeschaltet ist ( nicht ausgeschaltet )
*/
public boolean hatStrom()
{
if( StromLieferant != null )
return ( StromLieferant.hatStrom() == true && ein == true );
else return false;
}
/**
* Prinzip Kippschalter.
* Wenn ein- dann ausschalten und umgekehrt
* Wenn beim Einschalten der Lieferant Strom hat, dann bekommt der Konsument auch welchen
*/
public void schalten()
{
if( ein == false){
if( StromLieferant.hatStrom() == true )
StromKonsument.setStrom( true );
ein = true;
}
else if( ein == true ){
if( StromKonsument.hatStrom() == true )
StromKonsument.setStrom( false );
ein = false;
}
}
/**
* Bezeichnung zur Verwendung durch die toString()-Methoden
*/
public String getBezeichnung()
{
return Bezeichnung;
}
/**
* Ausgabe von Bezeichnung sowie Lieferanten und Konsumenten, falls vorhanden
*/
public String toString()
{
String LiefBez = "?";
String KonsBez = "?";
if( StromLieferant != null )
LiefBez = StromLieferant.getBezeichnung();
if( StromKonsument != null )
KonsBez = StromKonsument.getBezeichnung();
return "[ Schalter " +
Bezeichnung + " "
+( getEin() == true ? " ein " : " aus ")
+ ": " + LiefBez
+ " --> " + KonsBez
+ " ]";
}
}
//
/**
* Batterie ist Lieferant
*/
class Batterie implements Lieferant
{
private String Bezeichnung;
private boolean hatStrom;
private Konsument StromKonsument;
/**
*@param Bezeichnung ein Name für das Objekt Batterie
*/
public Batterie( String Bezeichnung )
{
this.Bezeichnung = Bezeichnung;
}
/**
* wird aufgerufen, wenn Verbindung hergestellt wird
* @see Draht
*/
public void setKonsument( Konsument e )
{
StromKonsument = e;
}
public boolean hatStrom()
{
return hatStrom;
}
public void setStrom( boolean lad )
{
hatStrom = lad;
}
/**
* hatStrom auf true setzen
*/
public void laden()
{
hatStrom = true;
}
/**
* Bezeichnung zur Verwendung durch die toString()-Methoden
*/
public String getBezeichnung()
{
return Bezeichnung;
}
/**
* Ausgabe von Bezeichnung und hatStrom
*/
public String toString()
{
return "[ Batterie " +
Bezeichnung + " "
+( hatStrom() == true ? " voll" : " leer")
+ " ]";
}
}
/** Hauptklasse schaltet Bauteile mi hilfe von Draht zusammen*/
public class Schaltung1
{
public static void main( String [] args )
{
/////// ERSTES SZENARIO
//
////// Batt -> Schalt2 -> Schalt1 -> Birn
//Gluehbirne erzeugen
Gluehbirne g1 = new Gluehbirne( "Birne1" );
System.out.println( g1 );
//Schalter1 erzeugen
Schalter s1 = new Schalter( "Schalter1" );
System.out.println( s1 );
// Schalter1 --> Draht1 --> Gluehbirne1
Draht d1 = new Draht( "Draht1" );
d1.verbinden( s1, g1 );
System.out.println( d1 );
//Schalter2 erzeugen
Schalter s2 = new Schalter( "Schalter2" );
System.out.println( s2 );
// Schalter2 --> Draht3 --> Schalter1
Draht d3 = new Draht( "Draht3" );
d3.verbinden( s2, s1 );
System.out.println( d3 );
//Batterie erzeugen und laden
Batterie b1 = new Batterie( "Batterie1");
System.out.println( b1 );
b1.laden();
System.out.println( b1 );
// Batterie --> Draht2 --> Schalter2
Draht d2 = new Draht( "Draht2" );
d2.verbinden( b1, s2 );
System.out.println( d2 );
//beide Schalter je nachdem schalten:
s1.schalten();
s2.schalten();
//und anzeigen:
System.out.println( s1 );
System.out.println( s2 );
System.out.println( g1 );
System.out.println();
////// ENDE des Szenarios mit 2 Schaltern in Reihe
///// ZWEITES SZENARIO
/////Batterie -> Schalter -> Birne:
Gluehbirne g10 = new Gluehbirne( "Birne10" );
System.out.println( g10 );
Schalter s10 = new Schalter( "Schalter10" );
Batterie b10 = new Batterie( "Batterie10");
System.out.println( b10 );
Draht d10 = new Draht( "Draht10", b10, s10 );
System.out.println( d10 );
System.out.println( s10 );
b10.laden();
System.out.println( b10 );
Draht d20 = new Draht( "Draht20", s10, g10 );
System.out.println( d20 );
s10.schalten();
System.out.println( s10 );
System.out.println( g10 );
s10.schalten();
System.out.println( s10 );
System.out.println( g10 );
System.out.println();
/////// ENDE ZWEITES SZENARIO
////// DRITTES SZENARIO
//
////// Batt -> Birne
Gluehbirne g100 = new Gluehbirne( " g100");
Batterie b100 = new Batterie( "b100");
b100.laden();
Draht d100 = new Draht("", b100, g100 );
System.out.println( g100 );
System.out.println();
////// ENDE DRITTES
//////VIERTER VERSUCH
//
Batterie batterie1 = new Batterie( "Batterie1");
Draht draht1 = new Draht( "Draht1" );
Schalter schalter1 = new Schalter( "Schalter1" );
Draht draht2 = new Draht( "Draht2" );
Gluehbirne gluehbirne1 = new Gluehbirne( "Gluehbirne1" );
System.out.println( batterie1 );
System.out.println( schalter1 );
System.out.println( gluehbirne1 );
System.out.println( draht1 );
System.out.println( draht2 );
System.out.println();
draht1.verbinden( batterie1, schalter1 );
draht2.verbinden( schalter1, gluehbirne1 );
System.out.println( draht1 );
System.out.println( draht2 );
System.out.println( batterie1 );
System.out.println( schalter1 );
System.out.println( gluehbirne1 );
System.out.println();
batterie1.laden();
System.out.println( batterie1 );
System.out.println( gluehbirne1 );
System.out.println();
schalter1.schalten();
System.out.println( schalter1 );
System.out.println( gluehbirne1 );
System.out.println();
////////ENDE VIERTER
}
}
Nach oben