Taschenrechner mit OOP

Bullet1990

Mitglied
@sheel
Ich möchte die Rechenoperationen wie gesagt irgendwie zusammenfassen, das ist die erste Gruppe. Addition direkt von Calculator abzuleiten hilft auch nicht.

Wenn ich den Stack direkt im Konstruktor besetze, klappts, ansonsten erbt Addition nen leeren Stack.
Ich muss es also so hinkriegen, dass zwar alle auf denselben Stack zugreifen (Vererbung?) aber trotzdem zur Laufzeit der Stack verändert werden kann...
Sorry, hab mir dein Profilbild nicht angesehen. Bin dann automatisch davon ausgegangen, dass du ein Programmierer bist, da Programmiererinnen ein seltenes Gut sind :D.

Du könntest doch etwas anders vorgehen, das würde vermutlich auch dein Stack-Problem lösen. Ich würde die Klasse Calculator gar nicht erst an andere Klassen vererben. (So habe ich es zumindest aus deinem letzten Post verstanden).

Wie Sheel auch schon gefragt hat: Wie ist die Klasse Base definiert?

Also hier mal ein paar Dinge, die ich so anmerken könnte (sorry, war mal Tutor :p):
  • Setze memory als private. Felder sollten immer private sein und über getter und setter geholt/gesetzt werden (Guter Programmierstil/Konvention). Du brauchst dann natürlich eine Methode "push(double zahl)" und eine Methode "peek()" in der Klasse Calculator, um ein push auf memory durchzuführen oder einen peek.
  • Ich würde die klasse Addition als static Klasse behandeln. D. h. deren Methoden static machen. Die kannst du dann so verwenden: Addition.add().
  • Natürlich funktioniert der vorherige Punkt nicht, da add() keine Parameter übergeben wurden. Also würde ich deine private-Felder (sum1,sum2,resultAdd) entfernen. Stattdessen würde ich add wie folgt ändern: add(Stack<Double> stack). resultAdd ergibt sich ja dann in der Methode.
  • Was soll nun der stack als Parameter? Ganz einfach, du könntest den vorhandenen Stack aus der Klasse Calculator übergeben und in add() verwenden. So könnte die Methode innen aussehen:
Java:
public static Stack<Double> add(Stack<Double> stack)
{
     double sum1 = stack.pop();
     double sum2 = stack.pop();

     //Jetzt das, was auch immer du mit dem Ergebnis machen möchtest 
    // Du kannst den Rückgabetyp von add hier auch gerne als double ändern und das Ergebnis zurückgeben mit: return sum1+sum2;

     stack.push(sum1+sum2);

     //Hier könntest du auch den Code beenden, müsstest nur den Rückgabetyp dieser Methode zu void ändern, die Änderungen müssten in stack gespeichert bleiben.

     //Falls du aber den ganzen Stack zurückgeben willst oder falls die Änderungen doch nicht gespeichert werden (müssten sie aber eigentlich):
     return stack;
}
  • Als nächstes würde ich für die Main-Methode eine eigene Klasse "Main" oder "Test" etc. schreiben, da dies schöner ist, als dies unbequem in die Klasse Calculator zu schreiben (Jedenfalls wird es so in den Unis gelehrt):
Java:
     public class Main
     {
          public static void main(String[] args)
          {
               Calculator calc = new Calculator();
               
              System.out.prinlnt("Zahlen ins Memory");
              calc.push(1);
              calc.push(2);

              System.out.println(calc.peek());

             Addition.add(calc.getStack());

            //Wenn hier der Stack unverändert bleibt dann einfach:   calc.setStack(Addition.add(calc.getStack()));

           System.out.println(calc.peek());
          }
     }
 

Bullet1990

Mitglied
@Bullet1990
Ja, sowas in der Art. Ich soll mich halt mit OOP vertraut machen und zeigen, ob ich die Grundprinzipien verstanden habe und anwenden kann.
Ich würde die Rechenoperationen gerne nochmal irgendwie "bündeln" wäre es sinnvoll, z.B. alle Grundrechenoperationen von einer (abstract) Class, alle Wurzel- und Potenzfunktionen von einer anderen (abstract) Class etc. abzuleiten? Oder gibts dafür nen besseren Weg?

P.S.: Sie, nicht er, soviel Zeit muss sein ;-)
Das ist bei den primitiven Grundrechenarten ein wenig schwierig. Ich wüsste nicht, wo es Sinn mach von einer abstrakten Klasse zu erben. Inbesondere, da ja alle ihren eigenen individuellen Rechenschritt haben. Gut du könntest höchstens die Potenz von der Multiplikation erben lassen und die Multiplikations-Methode n-mal in einer Schleife ausführen lassen. Du könntest auch die Wurzel dementsprechend implementieren, ohne Math.sqrt() zu verwenden. Aber wenn du die Berechnungs-Methoden static machst, wäre hier kein erben erforderlich. Die könntest du einfach so verwenden.

Wirklich Sinn macht es erst bei höheren Funktionen oder Folgen. Da könntest du die Summenfunktion (wie die Potenz) oder die Fibonacci-Folge durch die Addition realisieren. Auch könntest du einen Bruch-Rechner von der Division ableiten. Darunter fallen dann auch Funktionen, wie die Ackermann-Funktion, geometrische Reihe etc. Aber ich denke, dass ihr einen derartigen Rechner nicht implementieren müsst.

So oder so müsste man hier nicht wirklich erben, da die Methoden genau so gut statisch aufgerufen werden können.

Eigentlich ist der Rechner eine eher ungute Beispielaufgabe, um zu lernen, wie man Klassen verwendet. Ein schönes Beispiel ist die gute alte Bürohierarchie/Arbeiter-Beispielaufgabe. :)
 

ComFreek

Mod | @comfreek
Moderator
Ich würde folgende Klassen vorschlagen:
Java:
// Hat jemand einen besseren Namen?
public interface Calculable {
  public Stack<Double> calculate(Stack<Double> stack);
}

public class Addition implements Calculable {
  @Override
  public Stack<Double> calculate(Stack<Double> stack) {
    // ...
  }
}
Beim Rückgabetyp war ich mir nicht ganz sicher, was du genau zurückgegeben haben willst. Deswegen habe ich einfach das von Bullet übernommen.
Die Methode calculate() kann übrigens nicht als static deklariert werden, da sie aus einem Interface stammt: http://stackoverflow.com/questions/370962/why-cant-static-methods-be-abstract-in-java

Anwendung:
Java:
Calculator calc = new Calculator();
System.out.prinlnt("Zahlen ins Memory");
calc.push(1);
calc.push(2);
System.out.println(calc.peek());

Calculable add = new Addition();
add.calculate(calc.getStack());
Setze memory als private. Felder sollten immer private sein und über getter und setter geholt/gesetzt werden (Guter Programmierstil/Konvention).
Hier möchte ich widersprechen. Wenn man Klassen bzw. Objekte nur als reine Datenstruktur (à la POD - plain old data) nutzt, dann bringt es einem nichts, Getter und Setter zu verwenden.

@sheel [Offoptic: Es gibt noch comfreakPHP und comfreak1003 :D]
 

Bullet1990

Mitglied
Hier möchte ich widersprechen. Wenn man Klassen bzw. Objekte nur als reine Datenstruktur (à la POD - plain old data) nutzt, dann bringt es einem nichts, Getter und Setter zu verwenden.

Da hast du natürlich Recht. Ich bin nur davon ausgegangen, dass sie den Rechner in künftigen Aufgaben wiederverwenden wird oder ergänzen wird. Ihre Aufgabe zielt vermutlich auch auf die korrekte Verwendung von Gettern und Settern. Zu gerne sparen sich Java-Neulinge die Getter und Setter, indem die Felder einfach public deklariert werden. "Was soll da denn schon passieren?", denken sie sich dabei in der Regel. Daher wird es Anfängern ja immer eingeprügelt die Felder private zu halten. Sobald sie den nötigen Programmier-Skill haben, können sie selbst entscheiden, welche Variante dann die effizientere ist.
Ich weiß noch wie oft ich zu meiner Professorin gesagt habe "Macht es denn wirklich Sinn dies zu tun? Es ist ja nicht gerade die effizienteste Lösung". Immer bekam ich die Antwort "Die sollen das erstmal lernen, effizient Programmieren können sie später". :D
 

Saheeda

Mitglied
@Bullet1990

Danke, dein Beitrag von oben kam gerade richtig. Ich hab heute n paar Tipps bekommen, wie ich generell strukturierter bei sowas rangehen kann. Ich sollte dann nach dem neuen Entwurf nochmal von vorn anfangen und konnte deine Hinweise gleich mit einbauen.
Ich denke nicht, dass ich nochmal damit arbeiten soll (außer vielleicht bei den GUIs oder so...), aber er sollte _theoretisch_ jederzeit einfach erweiterbar sein, ohne an zig Stellen rumfummeln zu müssen.


btw:
Ich weiß, dass man ne Sprache nicht in n paar Tagen lernen kann, aber ist das "Niveau" mit dem Taschenrechner normal/hoch oder eher niedrig für rund eine Woche richtiges Programmieren? (Davor hatte ich mich v.a. mit Websprachen auseinandergesetzt)
 

sheel

I love Asm
Zum Btw: Schwer zu sagen, ohne den bisherigen Erfahrungsstand zu kennen.
Mit Websprachen ist PHP, JavaScript etc. gemeint?

Sich als Komplettanfänger als Erstes mit PHP und damit verbundenen Themen auseinanderzusetzen
kann bedeuten "ein Monat lang, zwei Stunden täglich" (und dann "glauben" dass man gut ist)
aber genau so gut "10 Jahre Vollzeit".

Nur paar Stichworte: PHP im Detail (Sprache, Programmierstile/patterns/bestpractices, innere Codestruktur
von PHP selber, dazu etwas C/C++ um das zu verstehen), paar wichtige Frameworks gut genug
um dafür Plugins etc. schreiben zu können, einen Abstecher in die Kryptographie und die relevante Mathematik,
Serveradministration (Installieren, Apacheconfig, Selinux, Schreiben eigener Kernelmodule...),
UX, Grafikdesign inkl. Zertifizierung in PS etc., usw.usw.


Wie viel man bei anderen Sprachen wiederverwenden kann hängt immer davon ab was man schon kann.
Man merkt deutlich, dass Java nicht dein Programmieranfang ist.
Aber ob es für dich für eine Woche gut oder schlecht ist können wir dir so auch nicht sagen.
 

Bullet1990

Mitglied
@Bullet1990

Danke, dein Beitrag von oben kam gerade richtig. Ich hab heute n paar Tipps bekommen, wie ich generell strukturierter bei sowas rangehen kann. Ich sollte dann nach dem neuen Entwurf nochmal von vorn anfangen und konnte deine Hinweise gleich mit einbauen.
Ich denke nicht, dass ich nochmal damit arbeiten soll (außer vielleicht bei den GUIs oder so...), aber er sollte _theoretisch_ jederzeit einfach erweiterbar sein, ohne an zig Stellen rumfummeln zu müssen.

Genau so sollte (vor allem am anfang) bei objektorientierten Sprachen gearbeitet werden. Du solltest immer so arbeiten, dass mögliche zukünftige Modifikationen durch möglichst niedrigen programmiertechnischen Aufwand ergänzt werden können. So sparst du dir relativ viel Arbeit.

btw:
Ich weiß, dass man ne Sprache nicht in n paar Tagen lernen kann, aber ist das "Niveau" mit dem Taschenrechner normal/hoch oder eher niedrig für rund eine Woche richtiges Programmieren? (Davor hatte ich mich v.a. mit Websprachen auseinandergesetzt)

Schwierig zu sagen. An sich behandelst du damit nur Grundkonzepte, die nicht schwer zu lernen sind. Ich finde aber, dass die Aufgabe ein relativ schlechtes Beispiel für OOP ist, weil es teilweise überhaupt keinen Sinn macht größtenteils Objekte zu verwenden. Du lernst im Prinzip objektorientiertes Programmieren auf Kosten der Softwarequalität. Ich finde, dass beides von Anfang an Hand in Hand gehen sollte.
Ein besseres Beispiel wäre eine Art Unternehmenshierarchie. Wo du eine abstrakte Klasse Arbeiter hättest, von der dann konkrete Klassen wie
Lagerarbeiter oder Büroarbeiter erben, die du dann anständig implementieren kannst. Zudem hättest du vielleicht noch eine abstrakte Klasse Kunde, von der dann registrierte Kunden und unregistrierte Kunden erben könnten. Dann haben diese Klassen dann noch Methoden, die Objekte anderer Klassen entgegennehmen (z.B. Büroarbeiter.prüftKundendaten(Kunde kunde)).
Solche Beispiele sind eigentlich typisch, wenn es darum geht Klassen und Objekte zu verwenden.
 

ComFreek

Mod | @comfreek
Moderator
Ich finde, dass man gute OOP-Prinzipien vor allem durch Praxis lernt. Man kann selbst erleben, warum ein bestimmtes Design Nachteile hat und warum das andere Vorteile hat.

OOP anhand von Klassen wie Büroarbeitern oder Autos (Autos --> LKW/PKW) zu lernen, kann für den Anfang durchaus sinnvoll sein. Ich selber fragte mich aber am Anfang des Programmierens immer, welche echten Beispiele es gebe, die wirklich in echten Codes angewendet werden. Vielleicht hilft es, nachdem man "theoretisch" sowas gelernt hat, sich Parallelen zu echten Codes aufzuzeigen (aufzeigen zu lassen).
Der eigene Fundus an Design/OOP-Wissen wächst mit jedem (guten) Code, den man verstanden / gelesen / benutzt hat.
 

Bullet1990

Mitglied
Ich finde, dass man gute OOP-Prinzipien vor allem durch Praxis lernt. Man kann selbst erleben, warum ein bestimmtes Design Nachteile hat und warum das andere Vorteile hat.

OOP anhand von Klassen wie Büroarbeitern oder Autos (Autos --> LKW/PKW) zu lernen, kann für den Anfang durchaus sinnvoll sein. Ich selber fragte mich aber am Anfang des Programmierens immer, welche echten Beispiele es gebe, die wirklich in echten Codes angewendet werden. Vielleicht hilft es, nachdem man "theoretisch" sowas gelernt hat, sich Parallelen zu echten Codes aufzuzeigen (aufzeigen zu lassen).
Der eigene Fundus an Design/OOP-Wissen wächst mit jedem (guten) Code, den man verstanden / gelesen / benutzt hat.
Da stimme ich dir voll und ganz zu. Als ich die jeweiligen Pflichtveranstaltungen in der Uni belegt habe, damals als Studienanfänger, habe ich die Programmier-Module gerade so mit 4.0 oder 3.7 bestanden. Das Problem war, dass ich nur das gemacht habe, was in den Aufgaben gestellt wurde.
Erst danach fing ich an mich an eigenen Projekten zu versuchen. Schon das erste Projekt, dass ich mit GUI fertig gestellt hat, hat mir die Augen geöffnet. Ich hab gesehen, wo ich relativ schlecht programmiert habe und wo ich hätte effizienter programmieren können. In zukünftigen Projekten habe ich dann immer den besseren Weg gewählt. Auch Fehler macht man nur die ersten Male. Beim nächsten Mal weiß man direkt, wie man etwas umgeht, ohne dass das Programm um die Ohren fliegt. Hätte ich früher angefangen aus eigenem Interesse zu programmieren, hätte ich die Module mindestens mit 2.0 bestanden. In einem Praktikum habe ich dann mitgeholfen eine Verwaltungsumgebung via PHP zu schreiben. Auch das hat unheimlich geschult.

Beim Programmieren gilt eigentlich immer: Learning by doing!