Programmierrichtlinen (Uni-Paderborn)
-
Ja, aber da vergleichst du ja trotzdem Äpfel mit Birnen. Ich sehe nicht wo C++ da einen unnötigen Overhead haben sollte. In C++ ist es hier nicht üblich wie in Java mit Zeigern zu arbeiten, aber die Objekte zu früh zu instanziieren ist ja auch nicht üblich. Ich vermute die Compiler sind schon intelligent genug die Instanziierungen zur rechten Zeit zu machen, aber nur, wenn dadurch der Programmablauf nicht verändert wird. Ich denke bei PODs und builtins sollte es hier kein Problem geben.
-
Ich denke auch, dass man Variable moeglichst lokal halten soll. Meint ihr, man sollte soweit gehen, dazu extra Bloecke aufzumachen, damit temporaete Variablen wieder aus dem Scope verschwinden?
... int result; { int tmp = ... int tmp2 = ... result = tmp * (tmp + tmp2); } ...
-
Nur, wenn es einen Destruktor-Aufruf zur Folge hat, sonst kannst es dir schenken. Komisch, hier gibt es irgendwie ständig die Idee, extra-Blöcke einzufügen, anstatt die Funktion weiter aufzuteilen.
Die Frage nach der Stelle, wo die Variable definiert wird, stellt sich doch gar nicht, wenn die Funktion nur 4 Zeilen lang ist. Also ist die Richtlinie sowieso nicht praxisrelevant.
void foo() { { ... } { ... } { ... } { ... } }
Oder zieht ihr so etwas tatsächlich einem
void foo() { tuedies(); tuedas(); ... tuejenes(); }
vor? Nicht wirklich, oder?
-
Unterfunktionsaufrufe schliesst mein Codefetzen doch nicht aus. Aber Du hast recht, dass ist ein manuelles Inlinen einer Funktion. Aber wenn die Funktion so speziell ist, muss es sich nicht unbedingt lohnen, das ganze auseinanderzureissen, der Uebersichtlichkeit wegen.
-
Ich finde nicht, dass es was mit speziell-sein zu tun hat. Ich kann ne Funktion immer aufteilen, und irgendwann ist die Grenze des Sinnvollen erreicht. Beispielsweise wäre es nicht mehr sinnvoll, eine Funktion zu schreiben, die mir eine int-Variable initialisiert. Amsonsten lassen sich schon wirklich fast alle Arbeitsschritte weiter sinnvoll aufteilen. Damit wird die Frage, ob Variablen an den Anfang eines Blocks gehören, komplett bedeutungslos und sehr lokal sind die Variablen auch.
Habe ich bedeutungslos gesagt? Ja stimmt auch, aber sie wird auch beantwortet. Ja, sie gehören an den Anfang des Blocks. Die Funktion ist zwei Zeilen lang, eine legt ne Variable an, die andere macht was damit. Vertauschen kann ich es nicht. Hach, wenn man nur alle Streitfragen so eindeutig lösen könnte.
-
komisch, dass dein Beispiel oben schon mehr als 2 codezeilen pro funktion enthält
-
Glaubst du nicht, ich könnte sie noch weiter zerlegen? Wenn es Sinn macht, tu ich es sofort. Kann man aber bei so Beispiel-Funktionen jetzt nicht entscheiden. Versuch mal, das im übertragenen Sinn zu sehen und nicht wortwörtlich zu nehmen.
Dir würde ich nahelegen, dass du nicht die Frage, ob du Variablen nach oben tust oder nicht entscheiden sollst, sondern dass du die Funktionen so klein machst, dass es kein richtiges oben und unten mehr gibt. Ob es 2 oder 5 Zeilen sind, spielt doch keine Rolle. Kein Mensch verliert in so einer Funktion die Übersicht, außer sie ist in Ook! geschrieben. Tatsächlich hat man in einer kleinen Funktion automatisch mehr die Tendenz, Variablen nach oben zu tun. Im Extrembeispiel von 2 Anweisungen ist es eh klar. Konstruktoraufrufe spart man sich hier auch nicht mehr, weil da eh schon die ganze Funktion nicht aufgerufen würde.
Solche Regeln wie "Variablen an den Anfang eines Blocks" sind für 200-Zeilen Monster geschaffen worden, um irgendwie den Anhauch von Übersichtlichkeit zu erhalten. Bei gescheiten Funktionen hast du nicht so die Wahl und machst einfach was gerade passt.
-
Was ist, wenn ich eine Funktion habe, wo an verschiedenen Stellen "returned" wird?
Was, wenn ich mit Exceptions programmiere und meine Funktion eine solche wirft?
Und was passiert, wenn ich in dieser Funktion am Anfang ein paar Objekte erstelle, die ich evtl. nur selten in dieser Funktion brauche, diese aber für ein Array mit 10.000 Elementen aufgerufen wird?Da werden die Objekte jedes Mal zu Beginn erstellt und am Ende wieder zerstört, obwohl ich gar nichts damit mache. Kann sein, dass ich das falsch sehe, aber wird da nicht u.U. ein enormer Performanceverlust in Kauf genommen?
Ob ich jetzt ein
int preis; ... preis = ...;
habe oder ein
... int preis = ...;
ist doch eigentlich völlig egal, weil ich die Variable (das Objekt) ja sowieso erst brauche, wenn ich das erste Mal etwas zuweise (bzw. erstelle und damit mache). Auch, wenn mein Compiler vielleicht viel optimiert, evtl. wird der Code auch mit einem anderen Compiler übersetzt, der nicht so dolle optimiert.
Um's kurz zu machen: Ich finde diese Richtlinie nicht so dolle.
-
Die meisten solcher Richtlinien sind bescheuert. Muß man ja einfach mal sagen. Genauso wie diese: "Alle Membervariablem müssen mit einem Unterstrich am Anfang versehen werden." Gibt es tatsächlich bei uns. Voll hohl!
// in irgend einer Klasse: public void foo(int a) { _b = _b + a; }
Ohne Unterstrichvorschrift:
// in irgend einer Klasse: public void foo(int a) { b = b + a; }
Kann mir jemand mal sagen, wo der Vorteil bei der ersten Variante sein soll? Wieso in Gottes Namen, soll ein Programmierer angeblich nicht an Variante 2 sehen können, das b eine Membervariable ist? Diesen Programmierer, der das nicht sieht, sollte nochmal über seinen Job nachdenken!
-
Optimizer schrieb:
Glaubst du nicht, ich könnte sie noch weiter zerlegen? Wenn es Sinn macht, tu ich es sofort. Kann man aber bei so Beispiel-Funktionen jetzt nicht entscheiden. Versuch mal, das im übertragenen Sinn zu sehen und nicht wortwörtlich zu nehmen.
Dir würde ich nahelegen, dass du nicht die Frage, ob du Variablen nach oben tust oder nicht entscheiden sollst, sondern dass du die Funktionen so klein machst, dass es kein richtiges oben und unten mehr gibt. Ob es 2 oder 5 Zeilen sind, spielt doch keine Rolle. Kein Mensch verliert in so einer Funktion die Übersicht, außer sie ist in Ook! geschrieben. Tatsächlich hat man in einer kleinen Funktion automatisch mehr die Tendenz, Variablen nach oben zu tun. Im Extrembeispiel von 2 Anweisungen ist es eh klar. Konstruktoraufrufe spart man sich hier auch nicht mehr, weil da eh schon die ganze Funktion nicht aufgerufen würde.
Solche Regeln wie "Variablen an den Anfang eines Blocks" sind für 200-Zeilen Monster geschaffen worden, um irgendwie den Anhauch von Übersichtlichkeit zu erhalten. Bei gescheiten Funktionen hast du nicht so die Wahl und machst einfach was gerade passt.es macht eben NICHT immer Sinn eine Funktion weiter zu zerlegen. Ja es ist sogar manchmal garnicht sinnvoll möglich, weil du dann ernorme schwierigkeiten mit variablen bekommst (grade bei java).. Auch wenn im Ansatz die Aussage richtig ist, übertreibst du es maßlos. Es KANN sinnvoll sein, aber zwanghaftes zerlegen von funktionen ist NICHT immer sinnvoll, sondern eben nur manchmal..
nehmen wir doch einfach das Beispiel von der ersten Seite. Natürlich kann man das ganze auch so schreiben:
public static void main (String [] args) { printDatumMauerfall(); } static void printDatumMauerfall() { int tag = 9; int monat = 11; int jahr = 1989; System.out.println("Datum des Mauerfalls:"); System.out.println(tag+" "+monat+" "+jahr); printAlterPreis(tag,monat,jahr); } static void printAlterPreis(int tag, int monat, int jahr) { double preis = 3.29; System.out.println("Preis einer Flasche Sekt am Tag des Mauerfalls in DM:"); System.out.println(preis); printNeuerPreis(tag,monat,jahr,preis); } static void printNeuerPreis(int tag, int monat, int jahr, double preis) { double neuerpreis = 2 * preis; System.out.println("Preis einer Flasche Sekt heute in EUR:"); System.out.println(neuerpreis); }
Das ist aber eben NICHT sinnvoll (die namensgebung der funktionen ist absichtlich scheiße)
-
mantiz schrieb:
Was ist, wenn ich eine Funktion habe, wo an verschiedenen Stellen "returned" wird?
Was, wenn ich mit Exceptions programmiere und meine Funktion eine solche wirft?
Und was passiert, wenn ich in dieser Funktion am Anfang ein paar Objekte erstelle, die ich evtl. nur selten in dieser Funktion brauche, diese aber für ein Array mit 10.000 Elementen aufgerufen wird?Was ist genau das Problem?
Da werden die Objekte jedes Mal zu Beginn erstellt und am Ende wieder zerstört, obwohl ich gar nichts damit mache. Kann sein, dass ich das falsch sehe, aber wird da nicht u.U. ein enormer Performanceverlust in Kauf genommen?
Richtig, wenn man nicht gescheit zerlegt. Ich konstruiere mit Sicherheit keine unnötigen Objekte.
Ich definiere Variablen auch erst, wenn ich sie brauche und aus technischer Sicht hast du völlig Recht. Grundsätzlich sind Definitionen mit Initialisierung sowieso schöner. Aber die besseren Funktionen von mir sind so kurz, dass die Variablen automatisch am Anfang stehen und dort initialisiert werden. Die Regel krampfhaft einzuhalten ist Unsinn, habe ich auch gesagt.
life schrieb:
es macht eben NICHT immer Sinn eine Funktion weiter zu zerlegen. Ja es ist sogar manchmal garnicht sinnvoll möglich, weil du dann ernorme schwierigkeiten mit variablen bekommst (grade bei java).. Auch wenn im Ansatz die Aussage richtig ist, übertreibst du es maßlos. Es KANN sinnvoll sein, aber zwanghaftes zerlegen von funktionen ist NICHT immer sinnvoll, sondern eben nur manchmal..
nehmen wir doch einfach das Beispiel von der ersten Seite. Natürlich kann man das ganze auch so schreiben:
public static void main (String [] args) { printDatumMauerfall(); } static void printDatumMauerfall() { int tag = 9; int monat = 11; int jahr = 1989; System.out.println("Datum des Mauerfalls:"); System.out.println(tag+" "+monat+" "+jahr); printAlterPreis(tag,monat,jahr); } static void printAlterPreis(int tag, int monat, int jahr) { double preis = 3.29; System.out.println("Preis einer Flasche Sekt am Tag des Mauerfalls in DM:"); System.out.println(preis); printNeuerPreis(tag,monat,jahr,preis); } static void printNeuerPreis(int tag, int monat, int jahr, double preis) { double neuerpreis = 2 * preis; System.out.println("Preis einer Flasche Sekt heute in EUR:"); System.out.println(neuerpreis); }
Das ist aber eben NICHT sinnvoll (die namensgebung der funktionen ist absichtlich scheiße)
Du hast Recht, diese Zerlegung ist nicht sinnvoll. printAlterPreis(), printNeuerPreis()? Denk mal nach, was hier nicht stimmt. printAlterPreis druckt den neuen Preis mit? Denk mal nach, was hier nicht stimmt. Außerdem sind die Funktionen zu lang.
Dass irgendwann eine Grenze des sinnvollen erreicht ist, habe ich selber bereits geschrieben. In diesem Beispiel ist das aber nicht der Fall, du zerlegst nur nicht richtig.
-
Optimizer schrieb:
Du hast Recht, diese Zerlegung ist nicht sinnvoll. printAlterPreis(), printNeuerPreis()? Denk mal nach, was hier nicht stimmt. printAlterPreis druckt den neuen Preis mit? Denk mal nach, was hier nicht stimmt. Außerdem sind die Funktionen zu lang.
Dass irgendwann eine Grenze des sinnvollen erreicht ist, habe ich selber bereits geschrieben. In diesem Beispiel ist das aber nicht der Fall, du zerlegst nur nicht richtig.
du hast es wohl immernoch nicht verstanden :(. Dabei war das Beispiel so einfach
. Nagut dann nochmal langsam zum mitschreiben: Die Namen sind absichtlich so gewählt, wie bereits geschrieben, um genau auf das Problem aufmerksam zu machen. Man kann es nunmal nicht die ganzen Aufrufe in die main packen, weil man eben noch die ganzen variablen braucht. Die alle zurückzugeben wäre zum einen sehr umständlich (referenzübergabe gibts nicht bei java oder?) und zum anderen hätteste dann dann genau das gleiche problem wie vorher, weil du ja nicht einfach schreiben darfst: int alterpreis = getAlterpreis();
Um zu gewährleisten, dass das Programm sich genauso verhält wie das ausgangsprogramm bekommt man halt so einen sinnlosen code. Kannst mich aber gern vom gegenteil überzeugen (kannst ja noch mehr funktionen benutzen wie du gesagt hast). Bedenke aber, dass die sichtbarkeit von den ganzen variablen nicht verändert werden darf, damit sich das programm auch wirklich so wie das ausgangsprogramm verhält. Vielleicht motiviert dich das ja mal endlich dein gehirn einzuschalten, denn ich glaube nicht, dass du wirklich so schwer von begriff bist, wie du hier tustPS: und komm mir nicht mit irgendwelchen globalen variablen o.ä., wie getJahr() {return 1989;}
-
Optimizer: Stellst du dir das so in etwa vor? Oder würdest du noch weiter zerlegen oder anders? Vielleicht die Methode printDatumMauerfall noch ein bischen zerlegen?
public static void main (String [] args) { printDatumMauerfall(); printAlterPreis(gibAlterPreis()); printNeuerPreis(berechneNeuerPreis(gibAlterPreis())); } public static void printDatumMauerfall() { int tag = 9; int monat = 11; int jahr = 1989; System.out.println("Datum des Mauerfalls:"); System.out.println(tag+" "+monat+" "+jahr); } public static void printAlterPreis(double preis) { System.out.println("Preis einer Flasche Sekt am Tag des Mauerfalls in DM:"); System.out.println(preis); } public static void printNeuerPreis(double neuerPreis) { System.out.println("Preis einer Flasche Sekt heute in EUR:"); System.out.println(neuerPreis); } public static double gibAlterPreis() { return 3.29; } public static double berechneNeuerPreis(double alterPreis) { return 2.0 * alterpreis; }
-
Gregor schrieb:
Optimizer: Stellst du dir das so in etwa vor? Oder würdest du noch weiter zerlegen oder anders? Vielleicht die Methode printDatumMauerfall noch ein bischen zerlegen?
und weils so schön ist, fällt mir jetzt grade ein, dass man für die für die preisberechnung die jahresdifferenz mitberücksichten muss also 2005-jahr und die Aussage
System.out.println("Preis einer Flasche Sekt heute in EUR:"); System.out.println(neuerPreis);
abgeändert werden soll in:
System.out.println("Preis einer Flasche Sekt heute in EUR:" + neuerPreis +", "+ " im Vergleich zum " + tag + "."+ monat + "." + jahr ", als der preis noch bei " + preis " lag :)");
und nun sag mir, welches programm wartbarer ist
btw. schick!
public static double gibAlterPreis() { return 3.29; }
und damit sich das nicht mit den lokalen variablen der funktion "abc" und "def" überscheidet nennen wirs lieber
public static double gibAlterPreisFuerFunktionMainZuVerwenden(){ return 3.29; }
-
Es ist ja in Ordnung kleine Funktionen zu machen, aber bei dem Beispiel ist es eindeutig unsinnig da mehr als eine Funktion daraus zu machen.
-
... schrieb:
Es ist ja in Ordnung kleine Funktionen zu machen, aber bei dem Beispiel ist es eindeutig unsinnig da mehr als eine Funktion daraus zu machen.
Natürlich ist das hier unsinnig. Ist ja nur ganz simpler Beispielcode ohne jede Art von Komplexität.
@life: Natürlich kannst einfach noch irgendwo ein gibDatumMauerfall() oder so einbauen und die Methodensignaturen der anderen Methoden entsprechend erweitern. Dann hast du genau die Wartbarkeit, die du haben möchtest und die printDatumMauerfall-Methode wird dadurch sogar noch kürzer. Die Benennung der Methoden ist auch eine Sache, die man einfach eindeutig machen muss. Wenn da eine neue Methode kommt, die einen ähnlichen Namen braucht, benennt man die Methode halt schnell um. Heutige IDEs bieten dafür Refactoring-Tools, die einem das in wenigen Sekunden durchführen lassen.
Bei diesem kleinen Codestück ist eine Argumentation mit Wartbarkeit unangebracht. Fast jede halbwegs vertretbare Realisierung dieses Programms hat keinerlei Probleme bezüglich der Wartbarkeit. Den Code überblickt man sofort und kann dann auch sofort die entsprechenden Änderungen vornehmen. Auch die dafür benötigte Zeit wird sich letztendlich nur gering unterscheiden.
Wenn du unterschiedliche Möglichkeiten der Wartbarkeit diskutieren möchtest, mach das lieber an einem Stück echten Codes. Bei folgendem Code habe ich bewußt längere Methoden gewählt. Das hat Performanzgründe, aber auch andere Gründe, die mit der Struktur des Codes zu tun haben. Ich hatte den Code hier schonmal zur Diskussion gestellt, aber da ist auch nicht wirklich etwas bei rausgekommen. Natürlich wurde vorgeschlagen, kleinere Methoden zu machen, bei mir hat das aber unter anderem auch dazu geführt, dass diese kleinen Methoden teilweise (übetrieben) 20 Parameter hatten (vielleicht waren es nur 10). Das kann es ja auch nicht sein. Andererseits ist der Code so wie er ist auch nicht gerade wartbar. Kannst ja mal ausprobieren, was passiert, wenn du ihn auf die Richtlinien deiner Uni umstellst.
Ich habe keine Ahnung, zu was das führt.
Wie würdest du diesen Code wartbar machen?
/* * LineCaster.java * * Created on 8. März 2005, 01:25 */ package jaradap.model.algorithm; import jaradap.model.algorithm.multiPointProcessor.RaycastProcessor; import jaradap.model.data.BasicRaster; import jaradap.model.data.StandardRaster; import math.linearAlgebra.Vector; /** * This class represents Objects which can analyze lines in a given raster. The analysis * projects a line into a single value which is given by a RaycastProcessor, the raster and the line. * * @author Gregor */ public class LineCaster { private final RaycastProcessor pointProcessor; private final StandardRaster raster; private final int dimension; /** * Creates a new LineCaster with the given parameters. * * @param pointProcessor This is the RaycastProcessor that will be used to analyze the lines * in the method castLine. * @param raster This is the raster which represents the environment in that this LineCaster * may analyze lines. */ public LineCaster(final RaycastProcessor pointProcessor, final StandardRaster raster) { this.pointProcessor = pointProcessor; this.raster = raster; dimension = raster.getDimensions(); } /** * This method analyzes the line specified by the parameters startPoint and endPoint. * The pointProcessor of this LineCaster is used to compute the resulting value, while the * raster of this LineCaster is the environment for the analysis. * * @param startPoint This is the start point of the line. * @param endPoint This is the end point of the line. * @return The value of the pointProcessor after processing all points of the line inside the raster * will be returned. If the line has no points inside the raster, 0 will be returned. */ public float castLine(final Vector startPoint, final Vector endPoint) { // Check parameters. if (startPoint.getDimension() != dimension) throw new IllegalArgumentException("startPoint has wrong dimension."); if (endPoint.getDimension() != dimension) throw new IllegalArgumentException("endPoint has wrong dimension."); // Clip line: // Resulting line is given by rasterStartPoint and rasterEndPoint. final int[] rasterStartPoint = new int[dimension]; final int[] rasterEndPoint = new int[dimension]; if(!setFirstPointInRaster(rasterStartPoint,startPoint,endPoint)) return 0.0f; if(!setFirstPointInRaster(rasterEndPoint,endPoint,startPoint)) return 0.0f; // Init helper variables. int maxDiffIndex = 0; final int[] intDifferences = new int[dimension]; final int[] relativePosition = new int[dimension]; final int[] position = new int[dimension]; final int[] increments = new int[dimension]; for(int i = 0 ; i < dimension ; ++i) { intDifferences[i] = rasterEndPoint[i] - rasterStartPoint[i]; increments[i] = (intDifferences[i] > 0) ? 1 : -1; intDifferences[i] = Math.abs(intDifferences[i]); if (intDifferences[i] > intDifferences[maxDiffIndex]) maxDiffIndex = i; relativePosition[i] = intDifferences[i] >> 1; position[i] = rasterStartPoint[i]; } final int maxDifference = intDifferences[maxDiffIndex]; final int maxIncrement = increments[maxDiffIndex]; // Process line: // 1. Reset pointProcessor. // 2. Process Bresenham-Line-Algorithm // 3. Return value of pointProcessor pointProcessor.reset(); for(;position[maxDiffIndex] != rasterEndPoint[maxDiffIndex] ; position[maxDiffIndex] += maxIncrement) { if (pointProcessor.addPoint(raster,position)) break; for(int i = 0 ; i < dimension ; ++i) { if (i == maxDiffIndex) continue; relativePosition[i] += intDifferences[i]; if (relativePosition[i] < maxDifference) continue; position[i] += increments[i]; relativePosition[i] -= maxDifference; } } pointProcessor.addPoint(raster,position); return pointProcessor.getValue(); } private final boolean setFirstPointInRaster(final int[] target, final Vector firstLinePoint, final Vector lastLinePoint) { // Compute the distance of the line's start- and endpoint in each direction. final double[] distances = new double[dimension]; double fraction = 0.0; for (int i = 0 ; i < dimension ; ++i) { distances[i] = (float)(lastLinePoint.getComponent(i) - firstLinePoint.getComponent(i)); } // Compute the fraction that represents the point where the line enters the raster. for (int i = 0 ; i < dimension ; ++i) { double newFraction = 0.0; final double component = firstLinePoint.getComponent(i); final double difference = distances[i]; final double maxValue = raster.getSize(i) - 1; if (component < 0.0) { if (difference <= 0.0) return false; newFraction = component / difference; } else if (component > maxValue) { if (difference >= 0.0) return false; newFraction = (component - maxValue) / difference; } if (newFraction < fraction) fraction = newFraction; } // Use the fraction to compute the first point of the line that lies within the raster // and check if the point really lies within the raster. // The point may not lie within the raster if there is no point of the line in the raster. for (int i = 0 ; i < dimension ; ++i) { target[i] = Math.round((float)(firstLinePoint.getComponent(i) - fraction * distances[i])); if (target[i] < 0) return false; if (target[i] > raster.getSize(i) - 1) return false; } return true; } }
-
Gregor schrieb:
Optimizer: Stellst du dir das so in etwa vor? Oder würdest du noch weiter zerlegen oder anders? Vielleicht die Methode printDatumMauerfall noch ein bischen zerlegen?
So find ich das nicht schlecht, auch wenn ich keine getter für Konstanten schreiben würde. Schau mal deine main() an, ist sie nicht wunderschön? Ist die Zerlegung hier in diesem Fall übertrieben? Ja, absolut. Aber nicht jeder Code macht nichts anderes als etwas einfaches auf der Konsole auszugeben, man muss halt ein einfaches Beispiel wählen.
... schrieb:
Es ist ja in Ordnung kleine Funktionen zu machen, aber bei dem Beispiel ist es eindeutig unsinnig da mehr als eine Funktion daraus zu machen.
Manchmal muss man halt übertreiben, um etwas rüberzubringen.
life schrieb:
Optimizer schrieb:
Du hast Recht, diese Zerlegung ist nicht sinnvoll. printAlterPreis(), printNeuerPreis()? Denk mal nach, was hier nicht stimmt. printAlterPreis druckt den neuen Preis mit? Denk mal nach, was hier nicht stimmt. Außerdem sind die Funktionen zu lang.
Dass irgendwann eine Grenze des sinnvollen erreicht ist, habe ich selber bereits geschrieben. In diesem Beispiel ist das aber nicht der Fall, du zerlegst nur nicht richtig.
du hast es wohl immernoch nicht verstanden :(. Dabei war das Beispiel so einfach
. Nagut dann nochmal langsam zum mitschreiben: Die Namen sind absichtlich so gewählt, wie bereits geschrieben, um genau auf das Problem aufmerksam zu machen.
Du hast nicht mal kapiert, was das Problem bei deiner Zerlegung war. Die Namen sind es nicht. Gregor hat es sauber gemacht.
1. Fehler: Eine Funktion heißt printIrgendwas, rechnet aber was aus und printed das dann. Das könnte man zerlegen. Später machst du noch irgendwas anderes mit dem Preis und müsstest ihn neu ausrechnen. Vielleicht wird das mal geändert, dass es nicht immer *2 ist, dann musst du alle Stellen, wo du das ausrechnest suchen und die Rechnung ändern.
2. Fehler: Eine Funktion heißt printAlterPreis und druckt den neuen Preis mit aus. Du hast einfach nur den Code so aufgeteilt, dass es keine Compilerfehler gibt, sinnvolles hast du nicht gemacht.
3. Fehler: Eine Funktion heißt printDatumMauerfall und druckt den alten Preis mit aus. Sie macht was anderes als sie heißt und sie macht ein Ding zu viel. Nein, 2, weil das druckt auch noch den neuen Preis aus.Man kann es nunmal nicht die ganzen Aufrufe in die main packen, weil man eben noch die ganzen variablen braucht. Die alle zurückzugeben wäre zum einen sehr umständlich (referenzübergabe gibts nicht bei java oder?) und zum anderen hätteste dann dann genau das gleiche problem wie vorher, weil du ja nicht einfach schreiben darfst: int alterpreis = getAlterpreis();
Um zu gewährleisten, dass das Programm sich genauso verhält wie das ausgangsprogramm bekommt man halt so einen sinnlosen code. Kannst mich aber gern vom gegenteil überzeugen (kannst ja noch mehr funktionen benutzen wie du gesagt hast). Bedenke aber, dass die sichtbarkeit von den ganzen variablen nicht verändert werden darf, damit sich das programm auch wirklich so wie das ausgangsprogramm verhält.Ui, jetzt hast du mir aber sauber zum Denken gegeben. Warum werden mir hier ständig non-Probleme hingeworfen? Wo ist denn das Problem bei Exceptions, Rückgabewerten? Warum darf ich die Sichtbarkeit von Variablen nicht ändern? Wie kommst du dazu, einfach mal in den Raum zu stellen, dass ich die Sichtbarkeit von Variablen nicht nach meinen Gutdünken verändern darf, weil es dann unmöglich ist, dass das Programm korrekt arbeitet? Ein bisschen Begründung wäre angebracht.
Vielleicht motiviert dich das ja mal endlich dein gehirn einzuschalten, denn ich glaube nicht, dass du wirklich so schwer von begriff bist, wie du hier tust
Mach einfach mal halblang. Ich muss von dir nichts lernen, du stehst noch ganz am Anfang, einen Millimeter neben der 0 auf einen Meter. Ich stehe schon mindestens einen cm neben der 0.
-
natürlich muss man bei solchen Aussagen von mir immer das einfache beispiel auf ein komplexeres programm übertragen. Natürlich ist das Argument der Wartbarkeit wenn man es streng auf dieses Beispiel beschränkt unsinn, aber es geht eben um das Prinzip. Und alle lokalen Variablen zu Klassenattribunten zu machen, kanns auch nicht sein, genausowenig wie Funktionen mit 20 Parametern zu haben, wie du es beschrieben hast. Man muss hier eben abwägen, ob es wirklich Sinn macht, diese Funktion weiter zu unterteilen. Eine pauschale Antwort kann es hier einfach nicht geben. Nichts weiter behaupte ich
Und um auch mal ein paar sinnlose Beispiele zu bringen.
template<class T> void CTerrain::submeshRefineEvenMorph(const int ownIndex,const int childIndex,const float ownY,const float childY, int* j,const int t,const int depth,const float leftY,const float rightY) { if(T::checkBounds && j[2] < maxIndex && j[6] < maxIndex) { if(T::checkVisible) { if(T::checkLeft && T::checkRight) submeshRefineEvenMorph<SNBVisible>(ownIndex,childIndex,ownY,childY,j,t,depth,leftY,rightY); else if(T::checkLeft) submeshRefineEvenMorph<SNBOnlyLeftVisible>(ownIndex,childIndex,ownY,childY,j,t,depth,leftY,rightY); else submeshRefineEvenMorph<SNBOnlyRightVisible>(ownIndex,childIndex,ownY,childY,j,t,depth,leftY,rightY); } else { if(T::checkLeft && T::checkRight) submeshRefineEvenMorph<SNB>(ownIndex,childIndex,ownY,childY,j,t,depth,leftY,rightY); else if(T::checkLeft) submeshRefineEvenMorph<SNBOnlyLeft>(ownIndex,childIndex,ownY,childY,j,t,depth,leftY,rightY); else submeshRefineEvenMorph<SNBOnlyRight>(ownIndex,childIndex,ownY,childY,j,t,depth,leftY,rightY); } } else { int CCLIndex; int CCRIndex; float rX, rY, rZ; float lX, lY, lZ; float lM; float rM; CViewFrustrum::IntersectionType leftType; CViewFrustrum::IntersectionType rightType; bool refineLeft = depth > 2; bool refineRight = refineLeft; //first get child-child-indices if(refineLeft) { if(T::checkLeft) { if(T::checkBounds) CCLIndex = shiftRight((int)maxIndex+getChild(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),depth-2); else CCLIndex = shiftRight((int)maxIndex+getChildNB(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),depth-2); } if(T::checkRight) { if(T::checkBounds) CCRIndex = shiftRight((int)maxIndex+getChild(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),depth-2); else CCRIndex = shiftRight((int)maxIndex+getChildNB(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),depth-2); } if(T::checkLeft) { getXYZ(CCLIndex,lX,lY,lZ); if(T::checkVisible) { if(depth < lazyDepth) { leftType = CViewFrustrum::In; refineLeft = (lM = checkRefineMorph(CCLIndex,lX,lY,lZ)) > 0; } else refineLeft = (lM = checkRefineMorph(CCLIndex,lX,lY,lZ,leftType)) > 0; } else refineLeft = (lM = checkRefineMorph(CCLIndex,lX,lY,lZ)) > 0; } if(T::checkRight) { getXYZ(CCRIndex,rX,rY,rZ); if(T::checkVisible) { if(depth < lazyDepth) { rightType = CViewFrustrum::In; refineRight = (rM = checkRefineMorph(CCRIndex,rX,rY,rZ)) > 0; } else refineRight = (rM = checkRefineMorph(CCRIndex,rX,rY,rZ,rightType)) > 0; } else refineRight = (rM = checkRefineMorph(CCRIndex,rX,rY,rZ)) > 0; } } if(!(T::checkLeft && refineLeft && (!T::checkVisible || leftType != CViewFrustrum::IntersectionType::Out))) { if(!(T::checkRight && refineRight && (!T::checkVisible || rightType != CViewFrustrum::IntersectionType::Out))) { addIndexedTriangle(childIndex,(depth-1)&1); addIndexedTriangle(ownIndex,(depth)&1); } else { addIndexedTriangle(childIndex,(depth-1)&1); addIndexedTriangle(ownIndex,(depth)&1); float rightLeftY = ownY; float rightApexY = (ownY+rightY)*0.5f; float rightRightY = rightY; float rightChildY = (rM*rY+(1-rM)*rightApexY); WORD CCRIBIndex = addVertex(rX,rightChildY,rZ); if(T::checkBounds) { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SOnlyRightVisible>(childIndex,CCRIBIndex,childY,rightChildY,getChild(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChild(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChild(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); else submeshRefineOddMorph<SOnlyRight>(childIndex,CCRIBIndex,childY,rightChildY,getChild(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChild(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChild(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); } else { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SNBOnlyRightVisible>(childIndex,CCRIBIndex,childY,rightChildY,getChildNB(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); else submeshRefineOddMorph<SNBOnlyRight>(childIndex,CCRIBIndex,childY,rightChildY,getChildNB(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); } } } else { if(!(T::checkRight && refineRight && (!T::checkVisible || rightType != CViewFrustrum::IntersectionType::Out))) { float leftLeftY = leftY; float leftApexY = (leftY+ownY)*0.5f; float leftRightY = ownY; float leftChildY = (lM*lY+(1-lM)*leftApexY); WORD CCLIBIndex = addVertex(lX,leftChildY,lZ); if(T::checkBounds) { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SOnlyLeftVisible>(childIndex,CCLIBIndex,childY,leftChildY,getChild(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChild(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChild(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); else submeshRefineOddMorph<SOnlyLeft>(childIndex,CCLIBIndex,childY,leftChildY,getChild(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChild(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChild(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); } else { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SNBOnlyLeftVisible>(childIndex,CCLIBIndex,childY,leftChildY,getChildNB(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); else submeshRefineOddMorph<SNBOnlyLeft>(childIndex,CCLIBIndex,childY,leftChildY,getChildNB(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); } addIndexedTriangle(ownIndex,(depth)&1); addIndexedTriangle(childIndex,(depth-1)&1); } else { float leftLeftY = leftY; float leftApexY = (leftY+ownY)*0.5f; float leftRightY = ownY; float leftChildY = ((lM*lY)+(1-lM)*leftApexY); WORD CCLIBIndex = addVertex(lX,leftChildY,lZ); if(T::checkBounds) { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SVisible>(childIndex,CCLIBIndex,childY,leftChildY,getChild(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChild(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChild(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); else submeshRefineOddMorph<S>(childIndex,CCLIBIndex,childY,leftChildY,getChild(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChild(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChild(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); } else { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SNBVisible>(childIndex,CCLIBIndex,childY,leftChildY,getChildNB(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); else submeshRefineOddMorph<SNB>(childIndex,CCLIBIndex,childY,leftChildY,getChildNB(j[0],j[2],j[6],depth,ltk[t][0],j[ltk[t][0]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][1],j[ltk[t][1]]),getChildNB(j[0],j[2],j[6],depth,ltk[t][2],j[ltk[t][2]]),(3-t)%4,depth-1,leftLeftY,leftRightY); } addIndexedTriangle(ownIndex,depth&1); float rightLeftY = ownY; float rightApexY = (ownY+rightY)*0.5f; float rightRightY = rightY; float rightChildY = (rM*rY+(1-rM)*rightApexY); WORD CCRIBIndex = addVertex(rX,rightChildY,rZ); if(T::checkBounds) { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SVisible>(childIndex,CCRIBIndex,childY,rightChildY,getChild(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChild(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChild(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); else submeshRefineOddMorph<S>(childIndex,CCRIBIndex,childY,rightChildY,getChild(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChild(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChild(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); } else { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineOddMorph<SNBVisible>(childIndex,CCRIBIndex,childY,rightChildY,getChildNB(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); else submeshRefineOddMorph<SNB>(childIndex,CCRIBIndex,childY,rightChildY,getChildNB(j[0],j[2],j[6],depth,rtk[t][0],j[rtk[t][0]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][1],j[rtk[t][1]]),getChildNB(j[0],j[2],j[6],depth,rtk[t][2],j[rtk[t][2]]),(4-t)%4,depth-1,rightLeftY,rightRightY); } } } } } template<class T> void CTerrain::submeshRefineOddMorph(const int ownIndex,const int childIndex,const float ownY,const float childY,const int index0,const int index1,const int index3,const int t,const int depth,const float leftY,const float rightY) { if(T::checkBounds && index1 < maxIndex && index3 < maxIndex) { if(T::checkVisible) { if(T::checkLeft && T::checkRight) submeshRefineOddMorph<SNBVisible>(ownIndex,childIndex,ownY,childY,index0,index1,index3,t,depth,leftY,rightY); else if(T::checkLeft) submeshRefineOddMorph<SNBOnlyLeftVisible>(ownIndex,childIndex,ownY,childY,index0,index1,index3,t,depth,leftY,rightY); else submeshRefineOddMorph<SNBOnlyRightVisible>(ownIndex,childIndex,ownY,childY,index0,index1,index3,t,depth,leftY,rightY); } else { if(T::checkLeft && T::checkRight) submeshRefineOddMorph<SNB>(ownIndex,childIndex,ownY,childY,index0,index1,index3,t,depth,leftY,rightY); else if(T::checkLeft) submeshRefineOddMorph<SNBOnlyLeft>(ownIndex,childIndex,ownY,childY,index0,index1,index3,t,depth,leftY,rightY); else submeshRefineOddMorph<SNBOnlyRight>(ownIndex,childIndex,ownY,childY,index0,index1,index3,t,depth,leftY,rightY); } } else { int j[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; //first compute j[0],j[2],j[6] since it is need in even tree getChildNB(index0,index1,index3,depth-1,0,j[0]); getChildNB(index0,index1,index3,depth-1,2,j[2]); getChildNB(index0,index1,index3,depth-1,6,j[6]); //get triangletype t for right and left children int tl = (3-t)%4; int tr = (4-t)%4; //now compute CCL and CCR int CCLIndex; if(T::checkLeft) { if(T::checkBounds) { if(ct[tl] == 5) { if(getChild(index0,index1,index3,depth-1,5,j[5]) >= maxIndex) CCLIndex = (int)maxIndex + shiftRight((size-1)+j[5] - (int)maxIndex,(depth-1)>> 1); else CCLIndex = shiftRight((int)maxIndex + j[5],depth-2); } else if(ct[tl] == 7) { if(getChild(index0,index1,index3,depth-1,7,j[7]) >= maxIndex) CCLIndex = (int)maxIndex + (size-1) + shiftRight(j[7] - (int)maxIndex,(depth-1)>> 1); else CCLIndex = shiftRight((int)maxIndex + j[7],depth-2); } else CCLIndex = shiftRight(maxIndex+getChild(index0,index1,index3,depth-1,ct[tl],j[ct[tl]]),depth-2); } else { CCLIndex = shiftRight(maxIndex+getChildNB(index0,index1,index3,depth-1,ct[tl],j[ct[tl]]),depth-2); } } int CCRIndex; if(T::checkRight) { if(T::checkBounds) { if(ct[tr] == 5) { if(getChild(index0,index1,index3,depth-1,5,j[5]) >= maxIndex) CCRIndex = (int)maxIndex + shiftRight((size-1)+j[5] - (int)maxIndex,(depth-1)>> 1); else CCRIndex = shiftRight((int)maxIndex + j[5],depth-2); } else if(ct[tr] == 7) { if(getChild(index0,index1,index3,depth-1,7,j[7]) >= maxIndex) CCRIndex = (int)maxIndex + (size-1) + shiftRight(j[7] - (int)maxIndex,(depth-1)>> 1); else CCRIndex = shiftRight((int)maxIndex + j[7],depth-2); } else CCRIndex = shiftRight(maxIndex+getChild(index0,index1,index3,depth-1,ct[tr],j[ct[tr]]),depth-2); } else { CCRIndex = shiftRight(maxIndex+getChildNB(index0,index1,index3,depth-1,ct[tr],j[ct[tr]]),depth-2); } } CViewFrustrum::IntersectionType leftType; CViewFrustrum::IntersectionType rightType; float lX,lY,lZ; float rX,rY,rZ; bool refineLeft; float lM; if(T::checkLeft) { getXYZ(CCLIndex,lX,lY,lZ); if(T::checkVisible) { /*if(depth < lazyDepth) { leftType = CViewFrustrum::In; refineLeft = (lM=checkRefineMorph(CCLIndex,lX,lY,lZ)) > 0; } else*/ refineLeft = (lM=checkRefineMorph(CCLIndex,lX,lY,lZ,leftType)) > 0; } else refineLeft = (lM=checkRefineMorph(CCLIndex,lX,lY,lZ)) > 0; } bool refineRight; float rM; if(T::checkRight) { getXYZ(CCRIndex,rX,rY,rZ); if(T::checkVisible) { /*if(depth < lazyDepth) { rightType = CViewFrustrum::In; refineRight = (rM=checkRefineMorph(CCRIndex,rX,rY,rZ)) > 0; } else*/ refineRight = (rM=checkRefineMorph(CCRIndex,rX,rY,rZ,rightType)) > 0; } else refineRight = (rM=checkRefineMorph(CCRIndex,rX,rY,rZ)) > 0; } if(!(T::checkLeft && refineLeft && (!T::checkVisible || leftType != CViewFrustrum::IntersectionType::Out))) { if(!(T::checkRight && refineRight && (!T::checkVisible || rightType != CViewFrustrum::IntersectionType::Out))) { addIndexedTriangle(childIndex,(depth-1)&1); addIndexedTriangle(ownIndex,(depth)&1); } else { addIndexedTriangle(childIndex,(depth-1)&1); addIndexedTriangle(ownIndex,(depth)&1); float rightLeftY = ownY; float rightApexY = (ownY+rightY)*0.5f; float rightRightY = rightY; float rightChildY = (rM*rY+(1-rM)*rightApexY); WORD CCRIBIndex = addVertex(rX,rightChildY,rZ); if(T::checkBounds) { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SOnlyRightVisible>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); else submeshRefineEvenMorph<SOnlyRight>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); } else { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SNBOnlyRightVisible>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); else submeshRefineEvenMorph<SNBOnlyRight>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); } } } else { if(!(T::checkRight && refineRight && (!T::checkVisible || rightType != CViewFrustrum::IntersectionType::Out))) { float leftLeftY = leftY; float leftApexY = (leftY+ownY)*0.5f; float leftRightY = ownY; float leftChildY = ((lM*lY)+(1-lM)*leftApexY); WORD CCLIBIndex = addVertex(lX,leftChildY,lZ); if(T::checkBounds) { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SOnlyLeftVisible>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); else submeshRefineEvenMorph<SOnlyLeft>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); } else { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SNBOnlyLeftVisible>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); else submeshRefineEvenMorph<SNBOnlyLeft>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); } addIndexedTriangle(ownIndex,(depth)&1); addIndexedTriangle(childIndex,(depth-1)&1); } else { float leftLeftY = leftY; float leftApexY = (leftY+ownY)*0.5f; float leftRightY = ownY; float leftChildY = ((lM*lY)+(1-lM)*leftApexY); WORD CCLIBIndex = addVertex(lX,leftChildY,lZ); if(T::checkBounds) { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SVisible>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); else submeshRefineEvenMorph<S>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); } else { if(T::checkVisible && leftType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SNBVisible>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); else submeshRefineEvenMorph<SNB>(childIndex,CCLIBIndex,childY,leftChildY,j,tl,depth-1,leftLeftY,leftRightY); } addIndexedTriangle(ownIndex,depth&1); float rightLeftY = ownY; float rightApexY = (ownY+rightY)*0.5f; float rightRightY = rightY; float rightChildY = (rM*rY+(1-rM)*rightApexY); WORD CCRIBIndex = addVertex(rX,rightChildY,rZ); if(T::checkBounds) { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SVisible>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); else submeshRefineEvenMorph<S>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); } else { if(T::checkVisible && rightType == CViewFrustrum::IntersectionType::Intersection) submeshRefineEvenMorph<SNBVisible>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); else submeshRefineEvenMorph<SNB>(childIndex,CCRIBIndex,childY,rightChildY,j,tr,depth-1,rightLeftY,rightRightY); } } } } }
natürlich kann man das noch weiter aufspalten in unterfunktionen, aber das führt sehr leicht zu den besagten 20 parameter funktionen (zumal die 2 funktionen sowieso schon extrem viele parameter haben >_<..
-
Optimizer schrieb:
Du hast nicht mal kapiert, was das Problem bei deiner Zerlegung war. Die Namen sind es nicht. Gregor hat es sauber gemacht.
1. Fehler: Eine Funktion heißt printIrgendwas, rechnet aber was aus und printed das dann. Das könnte man zerlegen. Später machst du noch irgendwas anderes mit dem Preis und müsstest ihn neu ausrechnen. Vielleicht wird das mal geändert, dass es nicht immer *2 ist, dann musst du alle Stellen, wo du das ausrechnest suchen und die Rechnung ändern.
2. Fehler: Eine Funktion heißt printAlterPreis und druckt den neuen Preis mit aus. Du hast einfach nur den Code so aufgeteilt, dass es keine Compilerfehler gibt, sinnvolles hast du nicht gemacht.
3. Fehler: Eine Funktion heißt printDatumMauerfall und druckt den alten Preis mit aus. Sie macht was anderes als sie heißt und sie macht ein Ding zu viel. Nein, 2, weil das druckt auch noch den neuen Preis aus.ok schaun wir mal aha 1. Fehler: schlechter name, 2. Fehler: schlechter name, 3. Fehler: schlechter name. Lesen müsste man können
. btw. ich reche sachen grundsätzlich nur einmal aus, wenn sich an den variablen nix geändert hat (perfomancegründe und so
)
Ui, jetzt hast du mir aber sauber zum Denken gegeben. Warum werden mir hier ständig non-Probleme hingeworfen? Wo ist denn das Problem bei Exceptions, Rückgabewerten? Warum darf ich die Sichtbarkeit von Variablen nicht ändern? Wie kommst du dazu, einfach mal in den Raum zu stellen, dass ich die Sichtbarkeit von Variablen nicht nach meinen Gutdünken verändern darf, weil es dann unmöglich ist, dass das Programm korrekt arbeitet? Ein bisschen Begründung wäre angebracht.
Rückgabewerte: man kann nur eins zurückgeben, jedefalls auf einfachem wege. Hat man aber viele Variablen die lokal in main sichtbar sein sollen, aber nicht global, bekomsmte probleme.
Sichtbarkeit: weil das Programm das verändert wird. Gut vielleicht ist es sinnvoll hier es zu verändern, aber nicht überall kannste die sichtbarkeit so sauber trennen. Bei meiner verschärfungen oben, bekommste damit gleich probleme (beim code von gregor)
Mach einfach mal halblang. Ich muss von dir nichts lernen, du stehst noch ganz am Anfang, einen Millimeter neben der 0 auf einen Meter. Ich stehe schon mindestens einen cm neben der 0.
ach die liebe Arroganz. Ich sag dir was: Du kannst jede Menge von mir lernen. Das heißt aber nicht, dass ich nichts von dir lernen kann :).
Btw. worauf begründest du deine Erhabenkeit eigentlich
-
life: Dein Code gefällt mir aus einem ganz anderen Grund schon nicht.
Du hast eine ganze Menge if-else-Konstrukte, die zudem teilweise eine sehr ähnliche Struktur haben. Das ist eine Form von Redundanz, die man beseitigen kann. Teilweise geht das tatsächlich schon dadurch, dass man bestimmte Codestücke in Methoden zusammenfasst, teilweise gibt es andere Möglichkeiten da ran zu gehen. In Java nutze ich bei solchen Dingen oft Polymorphie. Das kannst du auch in meinem Code sehen. Ich habe da ein Objekt pointProcessor als Member in der Klasse. Das ist nur dafür da, unterschiedliche Verhaltensweisen meines Codes zu erzeugen. Statt dieser Membervariable hätte ich auch so eine if-else-Orgie machen können, um alle möglichen Verhaltensweisen einzubauen. Das ist aber nicht gut, weil da oft noch etwas dazukommt. Der Code wird dann lokal immer länger und damit unwartbarer. Ok, du hast da keinen Javacode, sondern C++. Ich weiß nicht, wie man da mit soetwas umgeht, aber es wird da auch ein Möglichkeit geben, solche if-Orgien zu vermeiden. Manchmal kann man soetwas auch dadurch lösen, dass man sich irgendwelche Tabellen anlegt, in denen man bestimmte Werte oder so nachguckt.