Kapselung Modellierung von Intervallen: Klasse Interval

mathrac

Mitglied
Hallo ihr Lieben, das ist mein erster Beitrag im Forum.

Es geht um diese Aufgabe: "Kapsle das Gemeinsame in der Klasse Intervall und verteile das Spezifische in die neuen Klassen OpenInterval und ClosedInterval." Das ist die ursprüngliche Klasse:

Code:
public class Interval {

    private int lowerBound;
    private int upperBound;
   
    public Interval() {
        this(0,0);
    }
   
    public Interval(Interval interval) {
        this(interval.lowerBound, interval.upperBound);
    }
   
    public Interval(int lowerBound, int upperBound) {
        this.lowerBound = lowerBound;
        this.upperBound = upperBound;
    }
   
    public static Interval copyInstance(Interval interval) {
        int lowerBound = interval.lowerBound;
        int upperBound = interval.upperBound;
        return new Interval(lowerBound, upperBound);
    }
   
    public boolean contains(double number) {
        if(isEmpty()) return false;
        if(number >= lowerBound && number <= upperBound) {
            return true;
        }
        return false;
    }
   
    public boolean contains(Interval interval) {
        if(isEmpty()) return false;
        if(interval.isEmpty()) return true;
        return contains(interval.lowerBound) && contains(interval.upperBound);
    }
   
    public boolean isDisjoint(Interval interval) {
        return isEmpty() || interval.isEmpty() ||lowerBound > interval.upperBound || upperBound < interval.lowerBound;
    }
   
    public Interval intersection(Interval interval) {
        if(isEmpty()) return this;
        if(interval.isEmpty()) return interval;
        return new Interval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
   
    public Interval hull(Interval interval) {
        if(isEmpty()) return interval;
        if(interval.isEmpty()) return this;
        return new Interval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
   
    public boolean isEmpty() {
        if(lowerBound == 0 && upperBound == 0) {
            return true;
        }
        return false;
    }
   
    public String toString() {
        if(isEmpty()) return "[]";
        return String.format("[%d, %d]", this.lowerBound, this.upperBound);
    }
   
    public boolean equals(Object object) {   
        if (! (object instanceof Interval)) return false;   
        Interval otherNumber = (Interval) object;   
        return this.lowerBound == otherNumber.getLowerBound() 
            && this.upperBound == otherNumber.getUpperBound();
    }
   
    public Interval clone() {   
        return new Interval(this.lowerBound, this.upperBound);
    }
   
    public int getLowerBound() {
        return lowerBound;
    }

    public void setLowerBound(int lowerBound) {
        this.lowerBound = lowerBound;
    }

    public int getUpperBound() {
        return upperBound;
    }

    public void setUpperBound(int upperBound) {
        this.upperBound = upperBound;
    }
   
}

Ich habe in einem Vorherigen Projekt "Intervall" realisiert. Nun habe ich probiert die funktionelle Methoden in die Sub. Klassen zu verschieben.

Code:
public class Interval {

    private int lowerBound;
    private int upperBound;
   
    public Interval() {
        this(0,0);
    }
   
    public Interval(Interval interval) {
        this(interval.lowerBound, interval.upperBound);
    }
   
    public Interval(int lowerBound, int upperBound) {
        this.lowerBound = lowerBound;
        this.upperBound = upperBound;
    }
   
    public boolean isDisjoint(Interval interval) {
        return isEmpty() || interval.isEmpty() ||lowerBound > interval.upperBound || upperBound < interval.lowerBound;
    }
   
    public Interval intersection(Interval interval) {
        if(isEmpty()) return this;
        if(interval.isEmpty()) return interval;
        return new Interval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
   
    public Interval hull(Interval interval) {
        if(isEmpty()) return interval;
        if(interval.isEmpty()) return this;
        return new Interval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
   
    public boolean contains(double number) {
        if(isEmpty()) return false;
        if(number > lowerBound && number < upperBound) {
                return true;
        }
        return false;
    }
   
    public boolean isEmpty() {
        if(lowerBound == 0 && upperBound == 0) {
            return true;
        }
        return false;
    }
   
    public boolean equals(Object object) {   
        if (! (object instanceof Interval)) return false;   
        Interval otherNumber = (Interval) object;   
        return this.lowerBound == otherNumber.getLowerBound() 
            && this.upperBound == otherNumber.getUpperBound();
    }
   
    public Interval clone() {   
        return new Interval(this.lowerBound, this.upperBound);
    }
   
    public int getLowerBound() {
        return lowerBound;
    }

    public void setLowerBound(int lowerBound) {
        this.lowerBound = lowerBound;
    }

    public int getUpperBound() {
        return upperBound;
    }

    public void setUpperBound(int upperBound) {
        this.upperBound = upperBound;
    }
   
}

Code:
public class OpenInterval extends Interval{

    private int lowerBound;
    private int upperBound;
   
    public OpenInterval() {
        super(0,0);
    }
   
    public OpenInterval(OpenInterval interval) {
        super(interval.lowerBound, interval.upperBound);
    }
   
    public OpenInterval(int lowerBound, int upperBound) {
        super(lowerBound,upperBound);
    }
   
    public static OpenInterval copyInstance(OpenInterval interval) {
        int lowerBound = interval.lowerBound;
        int upperBound = interval.upperBound;
        return new OpenInterval(lowerBound, upperBound);
    }
   
    public OpenInterval hull(OpenInterval interval) {
        if(isEmpty()) return interval;
        if(interval.isEmpty()) return this;
        return new OpenInterval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
   
    public OpenInterval intersection(OpenInterval interval) {
        if(isEmpty()) return this;
        if(interval.isEmpty()) return interval;
        return new OpenInterval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
   
    public boolean contains(double number) {
        if(isEmpty()) return false;
        if(number >= lowerBound && number <= upperBound) {
                return true;
        }
        return false;
    }
   
    @Override
    public OpenInterval clone() {   
        return new OpenInterval(this.lowerBound, this.upperBound);
    }
   
    public String toString() {
        if(isEmpty()) return "[]";
        return String.format("[%d, %d]", this.lowerBound, this.upperBound);
    }
   
    public boolean contains(OpenInterval interval) {
        if(isEmpty()) return false;
        if(interval.isEmpty()) return true;
        return contains(interval.lowerBound) && contains(interval.upperBound);
    }
     
    public int getLowerBound() {
            return lowerBound;
    }

    public void setLowerBound(int lowerBound) {
            this.lowerBound = lowerBound;
    }

    public int getUpperBound() {
            return upperBound;
    }

    public void setUpperBound(int upperBound) {
            this.upperBound = upperBound;
    }
}

Um das zu Testen, habe ich die folgende Testklasse:

Code:
public class IntervalTest {
   
    /**
     * Testprogramm für Intervalle.
     */

    public static void testOpenIntervals() {
        OpenInterval a = new OpenInterval(2, 5);
        System.out.format("a=%s", a);
        OpenInterval b = new OpenInterval(4, 6);
        System.out.format("%nb=%s", b);
        OpenInterval c = new OpenInterval(6, 9);
        System.out.format("%nc=%s", c);
        OpenInterval d = new OpenInterval(4,5);
        System.out.format("%ne=%s", d);
        OpenInterval empty = new OpenInterval();
        System.out.format("%nd=%s", empty);
        System.out.println();
       
        OpenInterval a2 = a.clone();
        System.out.format("%n%s geklont ergibt %s", a, a2);
        System.out.format("%nIs a2=%s equal to a=%s: -> %b", a2, a, a2.equals(a));
   
        OpenInterval b2 = OpenInterval.copyInstance(b);
        System.out.format("%n%s kopiert ergibt %s", b, b2);
        System.out.format("%nIs b2=%s equal to b=%s: -> %b", b2, b, b2.equals(b));
       
        System.out.format("%n%s.contains(%s) ? --> %b", a, empty, a.contains(empty));
        System.out.format("%n%s.contains(%s) ? --> %b", empty, a, empty.contains(a));
        System.out.format("%n%s.contains(%s) ? --> %b", empty, empty, empty.contains(empty));
        System.out.println();
   
        System.out.format("%n%s.hull(%s) = %s",   a, c, a.hull(c));
        System.out.format("%n%s.hull(%s).contains(%s) ? --> %b", a, c, b, a.hull(c).contains(b));
        System.out.println();
   
        System.out.format("%n%s.intersection(%s) = %s", a, c, a.intersection(c));
        System.out.format("%n%s.intersection(%s).isEmpty() ? --> %b", a, c, a.intersection(c).isEmpty());
        System.out.println();
   
       
        System.out.format("%n%s.disjoint(%s) ? --> %b", a, d, a.isDisjoint(d));
        System.out.format("%n%s.disjoint(%s) ? --> %b", a, c, a.isDisjoint(c));
        System.out.println();
       
        System.out.format("%n%s.intersection(%s) = %s", a, b, a.intersection(b));
        System.out.format("%n%s.intersection(%s).contains(%s) ? --> %b", a, b, b, ((OpenInterval) a.intersection(b)).contains(b));
        System.out.format("%n%s.intersection(%s).contains(%s) ? --> %b", a, b, d, a.intersection(b).contains(d));
    }

    public static void testCloseIntervals() {
        ClosedInterval a = new ClosedInterval(2, 5);
        System.out.format("a=%s", a);
        ClosedInterval b = new ClosedInterval(4, 6);
        System.out.format("%nb=%s", b);
        ClosedInterval c = new ClosedInterval(6, 9);
        System.out.format("%nc=%s", c);
        ClosedInterval d = new ClosedInterval(4,5);
        System.out.format("%ne=%s", d);
        ClosedInterval empty = new ClosedInterval();
        System.out.format("%nd=%s", empty);
        System.out.println();
       
        ClosedInterval a2 = a.clone();
        System.out.format("%n%s geklont ergibt %s", a, a2);
        System.out.format("%nIs a2=%s equal to a=%s: -> %b", a2, a, a2.equals(a));
       
        ClosedInterval b2 = ClosedInterval.copyInstance(b);
        System.out.format("%n%s kopiert ergibt %s", b, b2);
        System.out.format("%nIs b2=%s equal to b=%s: -> %b", b2, b, b2.equals(b));
       
        System.out.format("%n%s.contains(%s) ? --> %b", a, empty, a.contains(empty));
        System.out.format("%n%s.contains(%s) ? --> %b", empty, a, empty.contains(a));
        System.out.format("%n%s.contains(%s) ? --> %b", empty, empty, empty.contains(empty));
        System.out.println();
       
        System.out.format("%n%s.hull(%s) = %s",   a, c, a.hull(c));
        System.out.format("%n%s.hull(%s).contains(%s) ? --> %b", a, c, b, a.hull(c).contains(b));
        System.out.println();
       
        System.out.format("%n%s.intersection(%s) = %s", a, c, a.intersection(c));
        System.out.format("%n%s.intersection(%s).isEmpty() ? --> %b", a, c, a.intersection(c).isEmpty());
        System.out.println();
       
       
        System.out.format("%n%s.disjoint(%s) ? --> %b", a, d, a.isDisjoint(d));
        System.out.format("%n%s.disjoint(%s) ? --> %b", a, c, a.isDisjoint(c));
        System.out.println();
       
        System.out.format("%n%s.intersection(%s) = %s", a, b, a.intersection(b));
        System.out.format("%n%s.intersection(%s).contains(%s) ? --> %b", a, b, b, a.intersection(b).contains(b));
        System.out.format("%n%s.intersection(%s).contains(%s) ? --> %b", a, b, d, a.intersection(b).contains(d));
    }

   
   
    public static void main(final String[] args) {
        testOpenIntervals();
        testCloseIntervals();
    }


}

Wenn ich diese nun ausführen möchte, kommt zwar kein Fehler mehr, dafür übernimmt er nicht die definierten Werte, sondern nur Nullen. Das ist die Ausgabe:

Code:
a=(0, 0)
b=(0, 0)
c=(0, 0)
e=(0, 0)
d=()

(0, 0) geklont ergibt ()
Is a2=() equal to a=(0, 0): -> true
(0, 0) kopiert ergibt ()
Is b2=() equal to b=(0, 0): -> true
(0, 0).contains(()) ? --> true
().contains((0, 0)) ? --> false
().contains(()) ? --> false

(0, 0).hull((0, 0)) = ()
(0, 0).hull((0, 0)).contains((0, 0)) ? --> false

(0, 0).intersection((0, 0)) = ()
(0, 0).intersection((0, 0)).isEmpty() ? --> true

(0, 0).disjoint((0, 0)) ? --> false
(0, 0).disjoint((0, 0)) ? --> true

(0, 0).intersection((0, 0)) = ()
(0, 0).intersection((0, 0)).contains((0, 0)) ? --> false
(0, 0).intersection((0, 0)).contains((0, 0)) ? --> falsea=[0, 0]

Ich sehe meinen Fehler nicht und google etc. können mir leider auch nicht helfen. Habt ihre vielleicht eine Idee, wo mein Fehler ist?

Beste Grüße
 
Das liegt daran, dass du die Attribute für Untergrenze und Obergrenze doppelt führst. Du setzt die Attribute der Oberklasse, liest aber die Attribute der Unterklasse aus.
Insgesamt finde ich aber bereits deine ursprüngliche Intervall-Implementierung ziemlich seltsam. Warum gilt beispielsweise das Intervall [0, 0] als leer? Es enthält doch immerhin die 0. Und warum ist das Intervall [1, 1] dann nicht auch leer? Und warum ergibt die Schnittmenge der Intervalle [1, 2] und [3, 4] eigentlich nicht das leere Intervall [], sondern [3, 2]? Ist das überhaupt ein gültiges Intervall?
 
Hallo,
deine Ausgabe bei openInterval ist immer Null,weil die Variablen
Java:
 private int lowerBound;
    private int upperBound;
null sind und den Aufruf von super() überdecken.
Zudem brauchst du keine getter und setter in der Open Interval Klasse, weil die ja von der Interval Klass vererbt werden.

Als Ausgabe erhalte ich folgendes:
2
5

b=[4, 6]
c=[6, 9]
e=[4, 5]
d=[]

[2, 5] geklont ergibt [2, 5]
Is a2=[2, 5] equal to a=[2, 5]: -> true
[4, 6] kopiert ergibt [4, 4]
Is b2=[4, 4] equal to b=[4, 6]: -> false
[2, 5].contains([]) ? --> true
[].contains([2, 5]) ? --> false
[].contains([]) ? --> false

[2, 5].hull([6, 9]) = [6, 5]
[2, 5].hull([6, 9]).contains([4, 6]) ? --> false

[2, 5].intersection([6, 9]) = [6, 9]
[2, 5].intersection([6, 9]).isEmpty() ? --> false

[2, 5].disjoint([4, 5]) ? --> false
[2, 5].disjoint([6, 9]) ? --> true

[2, 5].intersection([4, 6]) = [4, 6]
[2, 5].intersection([4, 6]).contains([4, 6]) ? --> false
[2, 5].intersection([4, 6]).contains([4, 5]) ? --> false

Interval:
Java:
public class Interval {

    private int lowerBound;
    private  int upperBound;
 
   
    public Interval(int lowerBound, int upperBound) {
        this.lowerBound = lowerBound;
        this.upperBound = upperBound;
    }
 
    public boolean isDisjoint(Interval interval) {
        return isEmpty() || interval.isEmpty() ||lowerBound > interval.upperBound || upperBound < interval.lowerBound;
    }
 
    public Interval intersection(Interval interval) {
        if(isEmpty()) return this;
        if(interval.isEmpty()) return interval;
        return new Interval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
 
    public Interval hull(Interval interval) {
        if(isEmpty()) return interval;
        if(interval.isEmpty()) return this;
        return new Interval(Math.max(lowerBound, interval.lowerBound),
                        Math.min(upperBound, interval.upperBound));
    }
 
    public boolean contains(double number) {
        if(isEmpty()) return false;
        if(number > lowerBound && number < upperBound) {
                return true;
        }
        return false;
    }
 
    public boolean isEmpty() {
        if(lowerBound == 0 && upperBound == 0) {
            return true;
        }
        return false;
    }
 
    public boolean equals(Object object) {
        if (! (object instanceof Interval)) return false;
        Interval otherNumber = (Interval) object;
        return this.lowerBound == otherNumber.getLowerBound()
            && this.upperBound == otherNumber.getUpperBound();
    }
 
    public Interval clone() {
        return new Interval(this.lowerBound, this.upperBound);
    }
 
    public  int getLowerBound() {
        return lowerBound;
    }

    public void setLowerBound(int lowerBound) {
        this.lowerBound = lowerBound;
    }

    public  int getUpperBound() {
        return upperBound;
    }

    public void setUpperBound(int upperBound) {
        this.upperBound = upperBound;
    }
}

OpenInterval:
Java:
public class OpenInterval extends Interval{

 
    public OpenInterval(int lowerBound, int upperBound) {
        super(lowerBound,upperBound);
    }
 
    public static OpenInterval copyInstance(OpenInterval interval) {
        int lowerBound = interval.getLowerBound();
        int upperBound = interval.getLowerBound();
        return new OpenInterval(lowerBound, upperBound);
    }
 
    public OpenInterval hull(OpenInterval interval) {
        if(isEmpty()) return interval;
        if(interval.isEmpty()) return this;
        return new OpenInterval(Math.max(getLowerBound(), interval.getLowerBound()),
                        Math.min(getUpperBound(), interval.getUpperBound()));
    }
 
    public OpenInterval intersection(OpenInterval interval) {
        if(isEmpty()) return this;
        if(interval.isEmpty()) return interval;
        return new OpenInterval(Math.max(interval.getLowerBound(), interval.getLowerBound()),
                        Math.min(interval.getUpperBound(), interval.getUpperBound()));
    }
 
    public boolean contains(double number, OpenInterval interval) {
        if(isEmpty()) return false;
        if(number >= interval.getLowerBound() && number <= interval.getUpperBound()) {
                return true;
        }
        return false;
    }
 
   @Override
    public OpenInterval clone() {
        return new OpenInterval(this.getLowerBound(), this.getUpperBound());
    }
 
    public String toString() {
        if(isEmpty()) return "[]";
        return String.format("[%d, %d]", this.getLowerBound(), this.getUpperBound());
    }
 
    public boolean contains(OpenInterval interval) {
        if(isEmpty()) return false;
        if(interval.isEmpty()) return true;
        return contains(interval.getLowerBound()) && contains(interval.getUpperBound());
    }
}

Interval Test:
Java:
public class IntervalTest {
   
    /**
     * Testprogramm für Intervalle.
     */

    public static void testOpenIntervals() {
   
OpenInterval a = new OpenInterval(2, 5);
        System.out.println(a.getLowerBound());
        System.out.println(a.getUpperBound());
 
        OpenInterval b = new OpenInterval(4, 6);
        System.out.format("%nb=%s", b);
        OpenInterval c = new OpenInterval(6, 9);
        System.out.format("%nc=%s", c);
        OpenInterval d = new OpenInterval(4,5);
        System.out.format("%ne=%s", d);
        OpenInterval empty = new OpenInterval(0, 0);
        System.out.format("%nd=%s", empty);
        System.out.println();
   
        OpenInterval a2 = a.clone();
        System.out.format("%n%s geklont ergibt %s", a, a2);
        System.out.format("%nIs a2=%s equal to a=%s: -> %b", a2, a, a2.equals(a));

        OpenInterval b2 = OpenInterval.copyInstance(b);
        System.out.format("%n%s kopiert ergibt %s", b, b2);
        System.out.format("%nIs b2=%s equal to b=%s: -> %b", b2, b, b2.equals(b));
   
        System.out.format("%n%s.contains(%s) ? --> %b", a, empty, a.contains(empty));
        System.out.format("%n%s.contains(%s) ? --> %b", empty, a, empty.contains(a));
        System.out.format("%n%s.contains(%s) ? --> %b", empty, empty, empty.contains(empty));
        System.out.println();

        System.out.format("%n%s.hull(%s) = %s",   a, c, a.hull(c));
        System.out.format("%n%s.hull(%s).contains(%s) ? --> %b", a, c, b, a.hull(c).contains(b));
        System.out.println();

        System.out.format("%n%s.intersection(%s) = %s", a, c, a.intersection(c));
        System.out.format("%n%s.intersection(%s).isEmpty() ? --> %b", a, c, a.intersection(c).isEmpty());
        System.out.println();

   
        System.out.format("%n%s.disjoint(%s) ? --> %b", a, d, a.isDisjoint(d));
        System.out.format("%n%s.disjoint(%s) ? --> %b", a, c, a.isDisjoint(c));
        System.out.println();
   
        System.out.format("%n%s.intersection(%s) = %s", a, b, a.intersection(b));
        System.out.format("%n%s.intersection(%s).contains(%s) ? --> %b", a, b, b, ((OpenInterval) a.intersection(b)).contains(b));
        System.out.format("%n%s.intersection(%s).contains(%s) ? --> %b", a, b, d, a.intersection(b).contains(d));
    }

    public static void main(final String[] args) {    
        testOpenIntervals();   
    }
}
Hoffe das hilft dir weiter.
 
Vielen Dank für deine Nachricht!

Ich hab das total vergessen, dass man die Getter und Setter in die Superklasse legen kann. Aber dadurch macht das alles wieder Sinn. Dann brauch ich nur noch die Attribute mit get versehen und dann weiß der Compiler schon wo er suchen muss. Du hast mir echt sehr geholfen!

Eine Anmerkung, bei der Klasse OpenInterval hast du den Fall

Code:
public ClosedInterval() {
        super(0,0);
}

glaube ich vergessen. Weil da zeigt er mir einen Fehler an, bei dem er diese Intervallart nicht einlesen kann.

Liebe Grüße
 
Hallo Meniskusschaden,

Das liegt daran, dass du die Attribute für Untergrenze und Obergrenze doppelt führst. Du setzt die Attribute der Oberklasse, liest aber die Attribute der Unterklasse aus.
Insgesamt finde ich aber bereits deine ursprüngliche Intervall-Implementierung ziemlich seltsam. Warum gilt beispielsweise das Intervall [0, 0] als leer? Es enthält doch immerhin die 0. Und warum ist das Intervall [1, 1] dann nicht auch leer? Und warum ergibt die Schnittmenge der Intervalle [1, 2] und [3, 4] eigentlich nicht das leere Intervall [], sondern [3, 2]? Ist das überhaupt ein gültiges Intervall?

Ja, das habe ich jetzt beseitigt, also die Doppelung und mit Hilfe des Getters geht das dann auch. Ja, das stimmt. Mathematisch gibt das auch keinen Sinn und ist ziemlich schlampig, ich als Mathematiker würde das auch nicht verwenden. Da ich aber nicht gerade so die Birne in Java bin, ist mir hier eher wichtig dass der Polymorphismus und die Vererbung richtig funktioniert. Dann kann ich jetzt auch hull() und disjunkt() anpassen, damit das auch mathematisch stimmt. Ich danke dir, dass du mich darauf hingewiesen hast.

Schönen Sonntag wünsche ich euch noch!

Liebe Grüße
 

Neue Themen


Zurück
Oben