angenommen, man hat vor(habe ich vor, mal sehen ob´s klappt) eine Biliothek zu schreiben, Die Mathematische Ausdrücke speichern, und mit ihnen rechnen soll.
Ich habe erstmal eine Abstrakte Basisklasse Term - daran ist nichts auszusetzten, oder? Davon leite ich später Klassen, wie Summ, Fraction, Root etc... die wiederum Instanzen der Klasse Term handhaben.
Meine Frage: Ich schreibe gerade die Klassendefinition, und führe abstrakte Operatoren ein. Beispiel :
public abstract Term operator+ (Term lhs, Term rhs);
so sieht meine Definition aus. Ist sie sinnvoll/richtig? Eigentlich soll ja auch jede Klasse, die von Term ableitet ihre eigene Logik definieren, wie sie sich mit anderen Termen Addieren lässt, aber es soll, je nach Summanden der Operator der endsprechenden Klasse aufgerufen werden, was ja mit den Parametern vom Typ erm schwierig wird, oder? Wenn eine Summe mit einer Summe addiert wird, muss man, um der Ausdruck möglichst weit zu vereinfachtn(ich gedenke Variablen etc zu erlauben) andere Logik anwenden, als wenn der Summand eine Wurzel darstellt.
Außerdem möchte ich nicht in der Implementation alles mit "if(typeof(rhs)==whatever)"
vollschreiben müssen. Wäre auch nicht das richtige, oder?
Vielleicht sollte nur die Klasse Sum wissen, wie man andere Objekte miteinander Addiert - dann müsste diese nach allen Typen differenzieren, bzw. den Operator für alle Typen überladen.
Kann man das vermeiden? Meine Lösung wird wahrscheinlich nicht gehen, oder?
Wäre sehr dankbar für ein paar Vorschläge, wie man das implementieren könnte.
Hallo ANSI_code,
eigentlich brauchst du nur die Klassen Term
, Operrator
und Literal
und vielleicht noch Variable
. Jedenfalls brauchst du keine Unterklassen für Summ
, Fraction
, Root
etc. und einen Term zu repräsentieren. Was die Berechnung angeht, könnte es dagegen praktisch oder nötig sein, solche Unterklassen zu haben. Die müssen dann aber nicht viel mehr tun, als eine abstrakte Methode Berechne
zu überschreiben.
Ist sie sinnvoll/richtig?
Ja, ja, die Frage nach dem Sinn. 😃
Nein, ich halte das nicht für sinnvoll. Zum einen bist du dann auf die Operatorsymbole festgelegt, die von C# unterstützt werden und zum anderen musst du dann alles hartcodieren. Mach eher eine Klasse Operator
mit einer String-Property Symbol
oder Name
.
BTW: In C# sind Operatoren statische Methoden und können daher nicht abstrakt sen.
herbivore
um einen abstrakten + operator zu machen könntest du allerdings eine abstrakte methode Add() machen, und diese im public static operator+ aufrufen.
loop:
btst #6,$bfe001
bne.s loop
rts
Die Addition mit den Operatoren würde ich jedenfalls in der Term-Klasse definieren, das hat sich bewährt. Aber sie muss gar nicht abstrakt sein, denn das einzige was sie machen wird ist eine neue Instanz deiner Add-Klasse erstellen und zurückgeben, also
Term1 + Term2 => Sum(Term1,Term2)
Außerdem möchte ich nicht in der Implementation alles mit "if(typeof(rhs)==whatever)"
vollschreiben müssen. Wäre auch nicht das richtige, oder?
Wenn du die Term Klasse mit abstrakten oder virtuellen Methoden wie Calculate, Expand, Simplify, Derive, etc. erweiterst und die entsprechenden Klassen wie Sum das selber machen lässt brauchst du erfahrungsgemäss nur sehr wenige solche Abfragen.
Vielleicht sollte nur die Klasse Sum wissen, wie man andere Objekte miteinander Addiert - dann müsste diese nach allen Typen differenzieren, bzw. den Operator für alle Typen überladen.
Ja, nur Sum sollte wissen wie addieren funktioniert, aber das heisst nicht dass Term nicht wissen darf dass es eine Addition gibt.
Tip: beschränke dich auf nur wenige skalare Datentypen (z.b. double), macht alles sehr viel einfacher.
Habe in C# übrigens schon diverse kleine computer algebra systeme geschrieben, der neuste Ansatz arbeitet direkt mit rohen Linq Expressions...
(PS: Der Palladium Prototyp (der Link von oben) ist speziell aufgebaut weil er direkt mit Linq Expressions arbeitet und die ganze Baumstruktur entsprechend nicht beeinflussen kann/will. Ist also wahrscheinlich eine komplett andere Architektur als bei dir und kaum übertragbar...)
war mir durchaus klar, trotzdem danke für den Hinweis.
Dann hoffe ich einfach mal, ich werde auch fertig. Bisher habe ich erst alle Klassen angelegt. Mit der Logik werde ich bestimmt noch eine Weile garnichts tu tun haben.
kann mir mal jemand erklären, warum mein Beitrag viel mehr Platz wegnimmt?
Hallo herbivore,
Jedenfalls brauchst du keine Unterklassen für
Summ
,Fraction
,Root
etc. und einen Term zu repräsentieren.
Wie würdest du denn z.B. den Term WURZEL(x - 1)
repräsentieren? Wäre es nicht praktisch, wenn es eine Klasse für die Wurzelfunktion gibt, die ihrerseits wieder einen Term als Radikanten enthalten kann?
Wie stellst du Brüche dar, sodass mit ihnen bequem gerechnet werden kann, wie Potenzen? Was ist mit komplexeren Gebilden wie Vektoren und Formen / Körper wie Dreiecken / Quadern, ...?
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
Hallo m0rius,
ich komme vom symbolischen Rechnen her. Daher habe ich da vielleicht eine zu spezifische Sichtweise (eingenommen). Wenn man tatsächlich arithmetisch rechnen will, muss man die die Operationen natürlich irgendwo implementieren.
herbivore
Hallo herbivore,
aber jetzt nochmal rein programmier- bzw. designtechnisch gesehen: Prinzipiell ist doch nichts gegen eine Klasse Fraction
mit Eigenschaften wie Numerator
& Denominator
und Methoden wie Add(Fraction fraction)
, Multiply(Fraction fraction)
und Reduce()
einzuwenden, oder?
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
Hallo m0rius,
es sind auf jeden Fall zwei ganz unterschiedliche Paar Schuh, ob es eine Klasse für Brüche oder eine Klasse für die Wurzelfunktion gibt. Bruch ist auch im Sinne der Objektorientierung eine super Klasse. Bei Wurzelfunktion muss man schon eine sehr abstrakte Sicht einnehmen, um das als annehmbare Klasse zu sehen.
herbivore
Hallo herbivore,
wo liegt denn hinsichtlich der "Klassenqualität" der Unterschied? Beide Klassen haben verschiedene Eigenschaften - ob diese nun "Nenner" oder "Radikant" heißen ist relativ egal - und Methoden. Okay, vll mag ein Bruch in er OOP mehr Methoden als eine Wurzel haben, aber ist denn ein Bruch nicht (zumindest fast) ebenso abstrakt wie eine Wurzel?
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg
Hallo m0rius,
Beide Klassen haben verschiedene Eigenschaften
ich sagte ja, dass wenn man eine sehr abstrakte Sichtweise einnimmt, auch die Wuzelfunktionsklasse annehmbar wird. Wenn man die die Semantik ins Spiel bringt, sieht es doch etwas differenzierter aus.
Da repräsentiert ein Bruch Daten. Samt den zugehörigen Operationen natürlich. Eine Klasse hat immer Zustand (Daten) und Verhalten (Operationen). Aber wenn man überlegt, welche Klassen es gibt, dann schaut man nur nach den Daten. Objektorientierung bedeutet auch Datenzentrierung, im Gegensatz zur prozeduralen Programmierung, der eine Operations-/Funktionszentrierung zu Grunde liegt.
Bruch repräsentiert also Daten, konkreter: rationalen Zahlen. Ok, ganz abstrakt gesehen steckt da eine Divisionsoperation hinter, aber im Grunde sind wir uns doch einig, dass Brüche einfach eine bestimmt Menge von Zahlen repräsentieren, eben die rationalen Zahlen.
Im Gegensatz dazu steht nun eine nach einer Funktion benannte und eine Funktion repräsentierende Klasse Wurzelfunktion. Und das ist vom Grundsatz her nicht erwünscht. Wenn man überlegt, welche Klassen es gibt, sollen man nicht nach den Funktionen schauen.
Natürlich ist die Problemdomäne hier die Repräsentation von Termen, da kann es dann schon sein, dass man die abstrakte Sichtweise einnehmen muss. Ich wollte ja auch nur das Problembewusstsein schärfen.
herbivore
Hallo herbivore,
[...], aber im Grunde sind wir uns doch einig, dass Brüche einfach eine bestimmt Menge von Zahlen repräsentieren, eben die rationalen Zahlen.
Okay, dieses Argument überzeugt.
Im Gegensatz dazu steht nun eine nach einer Funktion benannte und eine Funktion repräsentierende Klasse Wurzelfunktion.
Da leuchtet es ein, dass eben das nicht erwünscht ist.
Ich wollte ja auch nur das Problembewusstsein schärfen.
... was dir gelungen ist.
m0rius
Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg