Sind Richtlinien für das saubere Programmieren.
Die Reihenfolge der Attribute und Methoden sind wichtig. Es sollte versucht werden, Public Attribute zu vermeiden. Dafür sollten getter und setter Methoden angelegt werden.
Ideale Reihenfolge:
class Konto {
public String inhaber:
private int guthaben;
public Konto(){...}
public static ...
private static ...
public ueberweisung(...){...}
public getGuthaben(...){...}
public setGuthaben(...){...}
}
“Don’t talk to Strangers” also, nicht so etwas:
int i = getObj().getObj2().getObjA().getSomeOtherObject().getArray()[0];
Darum mit this
auf Objekte der Instanz zugreifen.
Das was in den Methodenname steht, sollte auch ausgeführt werden. Und nicht noch x-beliebige andere Aufgaben erfüllen.
Negativbeispiel:
class A {
private File SomeUnimportantFile;
File getUnimportantFile(){
launchNuklearMissile();
return SomeUnimportantFile;
}
launchNuklearMissile(){
//Destroy Everything!
}
}
Also bei Aufzählungen sollte die Reihenfolge beachtet werden. Bei Wochentagen z.B.: Montag, Dienstag … etc.
Auch Teile, die nicht erwartet werden, sollten raus gelassen werden, bei einer Aufzählung von Wochentagen sollte kein "Frei"
dabei sein.
Auch wenn "Frei"
der Tag ist, wo nicht gearbeitet wird.
Negativbeispiel:
enum Date {
FREITAG, DIENSTAG, MITTWOCH, FREI
}
Um das Beispiel von oben nochmal aufzugreifen, haben wir jetzt die unvorhersehbare Ausführung (launchNuklearMissile();
) entfernt.
class A {
private File SomeUnimportantFile;
File getUnimportantFile(){
return SomeUnimportantFile;
}
public launchNuklearMissile(){
//Destroy Everything!
}
}
Doch jetzt fällt uns auf, dass A
und getUnimportantFile
nicht gerade sehr aussagekräftig sind, hierfür sollten eindeutigere Bezeichner benutzt werden.
Beispiel:
class Waffenstillstand {
private File vertrag;
File getVertrag(){
return vertrag;
}
public launchNuklearMissile(){
//Destroy Everything!
}
}
Weitere interessante Bennung sind Doppelungen von Namen der Klasse sowie des Attributs und Methoden.
Negativbeispiel:
class Konto {
int kontoname;
}
Hier ist das Konto
zweimal drin.
Besser wäre sowas:
class Konto {
int name;
}
Zu Wenig ist zu wenig und zuviel ist zuviel.
Viele Fehler entstehen durch “Kopieren” und “Einfügen”. Ersetzen und durch Prozeduren/Funktionen.
Du wirst es nicht brauchen.
Negativbeispiel:
class Konto {
public bool ueberweisung(String empfaenger){...}
public bool indieSchweizueberweisung(String empfaenger){...}
}
Die Methode indieSchweizueberweisung
kann bei dem ersten Erscheinen eines Programmes für eine Bank überflüssig sein.
Eine Verantwortlichkeit pro Klasse.
class myConnector {
void connect(){...}
void terminateConnection(){...}
}
Eine send()
sowie eine receive()
Methode müssten in eine Seperate Classe ausgelagert werden.
class Communicator{
void send();
void receive();
}
Grob kann man sagen, eine Klasse nicht mehr als so ca. 200 Zeilen beinhalten sollte, oder um die 15 Methoden.
Open for extension closed for modification Es kann erweitert werden, aber es muss dazu nicht verändert werden.
Negativbeispiel:
class Form{...}
for Form f in FormListe{
switch(typeof(f)){
case Kreis: f.zeichneKreis();
case Quadrat: f.zeichneQuadrat();
}
}
Die switch case
Verzweigung muss jedes Mal neu angepasst werden,
wenn diese Art der Implementierung in der Code Bases öfter auftritt, muss das an jeder Stelle noch mal geändert werden. Darum sollte die Klasse Form
eine Methode draw()
zur Verfügung stellen
class Form{
zeichne();
}
for Form f in FormList:
f.draw();
Die Unterklasse z.B. Kreis
werden dann dazu gezwungen, eine Implementierung von draw()
zu übernehmen.
Vererbung, die nicht funktioniert:
class Rechteck{
float breit;
float hoch;
}
class Quadrat extends Rechteck{
// hoch === breit
}
Jedes Quadrat ist ein Rechteck, funktioniert in der Mathematik, aber nicht im programmiertechnischen Sinn.
Die Klasse Quadrat
kann nicht von Rechteck
erben, weil die Höhe immer gleich der Breite ist.
Andersherum geht das:
class Quadrat{
float breit;
flaeche(){
return breit * breit
}
}
class Rechteck extends Quadrat{
float hoch;
fläche(){
return hoch * breit
}
}
In diesem Beispiel muss die Methode flaeche()
noch Überschrieben werden.
Wenn von einem Interface geerbt wird, muss es auch gebraucht werden.
Negativ Beispiel:
interface Worker{
eat();
work();
}
class Mensch implements Worker{
work(){...}
eat(){...}
}
class Robot implements Worker{
work(){...}
eat(){} //<- Zuviel
}
Die Methode eat()
wird an die Klasse Robot mitgegeben, dies muss dann überschrieben werden und leer gelassen bleiben (Toter Code).
Besser wären in diesem Fall zwei Interfaces Eats
und Work
.
interface Eats{
eat();
}
interface Worker {
work();
}
class Mensch implements Eats, Worker{
work(){...}
eat(){...}
}
class Robot implements Worker{
work(){...}
}
In Software haben wir mehrere Schichten:
Eine CopyPast
Interface braucht z.B. zwei weitere Klassen namens ReadUserInput
und WriteFile
.
Das CopyPast
ist aus einer sehr hohen Schicht (fast in der GUI Schicht). Die Klassen ReadUserInput
und WriteFile
sind in einer niedrigeren Schicht (WriteFile
ist in der Persistenz Schicht).CopyPast
hängt in diesem Fall von den beiden Klassen ab, jedoch möchte man das Umgekehrte erreichen. Um das zu bewerkstelligen wird nun eine Classe erstellt, die sich in einer höhren Schicht befindet. In unserem Beispiel Reader
Klasse für ReadTextInput
und eine Writer
Classe für WriteFile
.
Methode hat eine Abstraktionsebene in der geblieben werden soll. Diese Abstraktionsebene sollten von Methode zu Methode abnehmen. Von der Abstrakteste Methode ruft nur Methoden auf, die von aussen für niemanden sichtbar sind. In diesen unteren Methoden verbergen dann die eigentlichen Rechenoperationen.
Man möchte den Code immer sauberer verlassen als man ihn Vorgefunden hat.
Nach aussen sollen sich Methoden nicht ändern. Was tun, wenn ein Parameter gebraucht wird, den es vorher nicht gab, einfache Lösung einsetzten default Parameter.
Nur mit Test Fallen bearbeiten, sonst besteht die Gefahr den Code zu zerstören, ohne es mitzubekommen.
Immer wenn du deinen eigenen Code nicht mehr verstehst, solltest du ihn überarbeiten.
Ordentlichkeit vor Performenz erst aufräumen, dann schnell machen.