OOP Methode überschreiben mit String-Paramter unterschiedlicher Größe?

membersound

Bekanntes Mitglied
Hallo,

wie kann ich folgende Methode überschreiben, deren Paramter einen String mit unterschiedlicher Länge ist?

Java:
//string.length() = 3
private void newObject(String[] string) {
}

//string.length = 5
public void newObject[String[] string) {
}

So geht es natürlich nicht, aber wie könnte ich es sonst machen? Außer natürlich der zweiten Methode einen anderen Namen zu geben...

Danke
 
deren Paramter einen String mit unterschiedlicher Länge ist?
In dem von Dir geposteten Code ist der Parameter ein String-Array. Und überschreiben hat was mit Vererbung zu tun. Du meinst hier glaub ich Überladen, also Methode mit selbem Namen aber unterschiedlichen Parametern. Java erkennt nur den Typen des Parameters (in dem Fall hier also String[]). Zwei Mal Methode mit gleichem Namen und String[] als Parameter geht nicht (hast Du ja auch schon rausgefunden). Die Länge spielt dabei keine Rolle. Was Du machen könntest, wäre folgendes:
Java:
public void processStringArr(String[] stringArr) {
  if (stringArr.length < 3)
    processSmallArr(stringArr);
  else
    processBigArr(stringArr);
}

private void processSmallArr(final String[] stringArr){
  ...
}

private void processBigArr(final String[] stringArr) {
 ...
}
Damit hättest Du nach außen nur eine Methode, die von Clients aufgerufen wird. Intern machst Du dann die Verarbeitung anhand der länge des Arrays.

So geht es natürlich nicht, aber wie könnte ich es sonst machen? Außer natürlich der zweiten Methode einen anderen Namen zu geben...
Im Prinzip doch der zweiten Methode einen anderen Namen geben...
 
Zuletzt bearbeitet von einem Moderator:
Im Prinzip doch der zweiten Methode einen anderen Namen geben...

Nja, eigentlich schon. Theoretisch könnte man versuchen, solchen Kram zu basteln:
Java:
class Marker3{}
class Marker5{}

class MyWeirdClass{
  public static final Marker3 THREE = new Marker3();
  public static final Marker5 FIVE = new Marker5();

  public method(String[] arr, Marker3 m){
    // just ignore m 
  }

  public method(String[] arr, Marker5 m){
    // just ignore m 
  }
}
aber es wäre eigentlich genauso umständlich, wie den methoden einfach zwei verschiedene Namen zu geben.

Frage: was hast du denn damit überhaupt vor? Wenn es sowas wie factory-methoden sind, dann wäre es vielleicht besser, drei bzw fünf Strings statt Arrays zu übergeben: dann wäre die Signatur unterschiedlich, und es gäbe weniger Raum für Fehler = besser für den Benutzer.
 
Also wenn ich davon ausgehe, dass sich beide Methoden in einer Klasse befinden, wäre da handling nach der Länge des String nicht viel passender?

Java:
private void newObject(String[] string) 
{
  if (string.length >=5)
    // Do something
  else
    // Do something else
}
 
Ich muss mal ein bisschen rumprobieren. Entweder ich nenn die Methode einfach um, oder ich mach das wirklich mit mit der Längenunterscheidung im Konstruktor.

Ich weiß jetzt gerade nicht, was Factory Methods sind, deshalb sag ich mal nein 😉
Das Überladen war ursprünglich dafür gedacht, dass ich ein Objekt mit der selben Methode, aber aus unterschiedlichen Quellen erzeugen kann. Einmal aus einem FileReader, und andermal aus einem Gui JDialog. Das Objekt, welches aus dem FileRead erstellt wird, bekommt allerdings mehr Parameter übergeben als aus der Gui.

Wahrscheinlich werde ich es jetzt so machen, dass ich aus einer einzigen newObject() Methode den Konstruktor aufrufe, und innerhalb dem Konstruktor dann die Fallunterscheidung vornehme. Wird wohl am saubersten sein?
 
was du eigentlich braeuchtes waer ein Interface und untersch. Implementierungen. Nicht eine Klasse mit allen moeglichen Methoden - keine ahnung aber ob dir das etwas sagt
 
Sagen wir mal so, ich habe bisher noch nicht mit Interfaces gearbeitet. Aber ist jetzt vl eine gute Gelegenheit zu verstehen wann man die benutzt, bzw was man damit vereinfachen kann.
Eigentlich ist ein Interface doch sowas wie ein Bauplan, der vorgibt welchen Methoden die Klassen haben müssen, die das Interface implementieren.
Falls dem so ist, sehe ich nicht wie ich das bei mir sinnvoll nutzen könnte.

Deshalb habe jetzt mal versucht meinen Code zu abstrahieren. Ist natürlich jetzt nicht besonders logisch konstruiert, aber ok: vl kannst du mir sagen, wie ich da ein Interface gewinnbringend einsetzen kann?

In einer Datei sind zwei Autotypen gespeichert. Eines davon (CustomCar) hat aber mehr Attribute als das andere. Es hat zb ein Herstellerdatum (createDate) und ist bereits lackiert (color).

Das CustomAuto aus der Gui ist jetzt aber zB noch nicht lackiert. Trotzdem brauche es von genau diesem Objekttyp.

Java:
//die beiden klassen
public class Car {
	private String name, ps;

	public Car (String[] s) {
		this.name = s[0];
		//...
	}
}

public class CustomCar extends Car {
	private String createDate, color;

	public CustomCar (String[] s) {
		super(s);
		this.createDate = s[2]
		this.color = s[3];
	}
}


//die get content methoden
public void fileRead() {
	//filereader füllt String[] s mit content
	newCar(s);
	newCustomCar(s);
}


public void guiReader() {
	//components getText() usw füllt String[] s mit content
	//wenn komponenten nicht eingetragen wurden (zb herstellerdatum oder farbe), dann werden diese empty gesetzt ""
	newCustomCar(s);
	//oder je nach gui-formular auch nur: newCar(s)
}

//die create objekt methoden
public void newCustomCar(String[] s) {
	//call constructor
	CustomCar myCust = new CustomCar(s);

	//...add to arraylist for further displaying in JList gui, etc
}

public void newCar(String[] s) {
	Car myCar = new Car(s);
}
 
Zuletzt bearbeitet:
Dein Code ist schon ein guter Ansatz. Er enthält aber einige Fehler/Unschönheiten:
-Zeile 5: Der String-Array als Parameter ist unschön. Besser wäre hier ein benamter Parameter "String name"
-Zeile 14: Du wolltest glaube ich einen Konstruktor für CustomCar schreiben. Der darf dann nicht Astra heißen sondern muss CustomCar heißen
-Zeile 14: Auch hier statt des Arrays lieber einzelne benamte Parameter verwenden. Das wären dann, "name, createDate, color". Du würdest dann super(name) aufrufen und danach this.createDate = createDate und this.color=color
-Zeilen 38 und 45: Das sollen wohl builder-Methoden sein. (Zumindest suggerieren deren Namen das.) Die dürfen dann aber nicht void zurück geben sondern Car bzw. CustomCar. Auch sollte man die Methoden static deklarieren. Die Parameterliste wäre analog zu dem jeweiligen Konstruktor.
 
Zuletzt bearbeitet von einem Moderator:
du musst dir ueberlegen was deine Methoden machen sollen.

Nehmen wir an du willst eine Struktur haben, die dir ein neues Auto erzeugt
Java:
public interface CarCreator {
   public Car createCar();
}

public class GuiCarCreator implements CarCreator {
   public Car createCar() {
       Car car = new Car("Astra"); // niemals String[] als grundlage fuer mehrere Parameter nehmen
       // was auch immer noch mit car geschehen soll - zb von einer UI gelesen
       return car;
   }
}

public class FileCarCreator implements CarCreator {
   public Car createCar() {
       // Car information von File lesen und dann 
       return car;
   }
}


public class CarApplication {
    private CarCreator carCreator;
    
    public CarApplication(CarCreator c) {
        carCreator = c;
    }

    public void foo() {
        Car car1 = carCreator.createCar();
        Car car2 = carCreator.createCar();
       // was auch immer damit geschieht
   }
}

public class Main {
    public static void main(String[] args)  {
        new CarCreator(new GuiCarCreator()).foo(); 
    }
}
so als bsp

-Zeilen 38 und 45: Das sollen wohl builder-Methoden sein. (Zumindest suggerieren deren Namen das.) Die dürfen dann aber nicht void zurück geben sondern Car bzw. CustomCar. Auch sollte man die Methoden static deklarieren. Die Parameterliste wäre analog zu dem jeweiligen Konstruktor.
Builder methoden geben den Builder an sich zurueck, nicht das halbfertige Objekt.
Und sollen auch nicht statisch sein ! Du kannst um den Builder zu starten eine statische methode anbieten. Die Buildermethoden selber sind bitte schoen non-static !
 
bygones hat gesagt.:
Builder methoden geben den Builder an sich zurueck, nicht das halbfertige Objekt.
Und sollen auch nicht statisch sein ! Du kannst um den Builder zu starten eine statische methode anbieten. Die Buildermethoden selber sind bitte schoen non-static !
Hast Recht, ich habe den falschen Terminus gewählt. Ich meinte nicht builder methods sondern static factory methods.
 
Zuletzt bearbeitet von einem Moderator:
Also statt dem Konstruktor einen String[] zu übergeben, setze ich lieber so 10 Parameter in den Konstuktor? Ist das besser als alles im Sting zu sammeln?

du musst dir ueberlegen was deine Methoden machen sollen.
Nehmen wir an du willst eine Struktur haben, die dir ein neues Auto erzeugt
Also ich hab echt Probleme wie ich das jetzt Designe, bzw mit der Struktur. Du hast ja jetzt eher für jede Funktionalität eine eigene Klasse geschrieben. Sollte man das tun? Mir erschließt sich das noch nicht ganz. Da muss ich ja ständig Objekte der Klasse erzeugen, dessen Methode ich nutzen will.


Ich hab in meinem Projekt einfach die Objektklasse und eine Modellklasse. In der Modellklasse habe ich halt die ganzen Methoden, ungefähr so:
-readMyFile
-writeMyFile
-createMyObject
-replaceMyObject
-addMyObject
-deleteMyObject
-modifyMyObject
-verifyMyObject
-und ein paar getter/setter

Die erstellten Objekte verwalte ich in einer private ArrayList<Object>. Auf den Array greife ich dann jeweils in den oben genannten Methoden zu. Dort werden denen die einzelne Objekte mit this.arrayList.add, remove, set usw verarbeitet. Um den array dann später in einer GUI JList darzustellen.

Bin ich damit jetzt sehr auf dem Holzweg und sollte das umschreiben?

Danke
 
Also statt dem Konstruktor einen String[] zu übergeben, setze ich lieber so 10 Parameter in den Konstuktor? Ist das besser als alles im Sting zu sammeln?
bei 10 Parametern ist eher alarm angesagt, dass du zuviel in der Klasse machst und man das besser trennen sollte. Zuviele Parameter in einer andere struktur zu verbergen ist nicht schoen.

Also ich hab echt Probleme wie ich das jetzt Designe, bzw mit der Struktur. Du hast ja jetzt eher für jede Funktionalität eine eigene Klasse geschrieben. Sollte man das tun? Mir erschließt sich das noch nicht ganz. Da muss ich ja ständig Objekte der Klasse erzeugen, dessen Methode ich nutzen will.
mach dir nicht so viel kopf am Anfang. Richtige Kapselung und Modularitaet sind nicht etwas was man am Anfang versteht und schnell lernt - das ist Erfahrungssache.

Aber im Prinzip soll man jeden Kontext fuer sich halten, d.h. unterschiedl. Funktionalitaeten gehoeren getrennt, zusammengehoerende gehoeren zusammen.

Bin ich damit jetzt sehr auf dem Holzweg und sollte das umschreiben?

Danke
nein aufm holzweg bist du nicht. Die struktur ist nicht optimal, da du z.b. das Objekt selber (mit seinen gettern/settern) mischt mit logik wie du es erstellst oder wie du es speicherst.

Aber wie gesagt - das sind sachen die erst nach einiger Erfahrung klar werden.
 
Ja, aber genau um das zu erlernen bin ich ja hier 🙂
Also ich merke immer wieder, dass mir die Umsetzung relativ leicht von der Hand geht, aber Struktur und Design so gar nicht.
Gibt es dafür ein gutes Buch?

Angenommen, ich würde jetzt die FileAccess Methoden (Read + Write) in eine eigene Klasse auslagern wollen. Wie würde ich das dann machen?

Java:
public class FileAccess {

	public ArrayList readFromFile() {
		//read, split, create objects, write them to ArrayList...
		return ArrayList;
	}

	public writeToFile(ArrayList myList) {
		//get elements in arrayList, write to file
	}
}



//im Model.java dann:
public class Model {

	new ArrayList myList =  new FileAccess().readFromFile();

	//modify, add, delete objects in myList

	new FileAccess().writeToFile(myList);

	
}

Dann müsste ich ja immer, wenn ich FileAccess brauche, ein Objekt dieser Klasse erstellen, also new FileAccess(). Sonst komm ich ja nicht an die Methoden. Ist das richtig so?
 
Zuletzt bearbeitet:
ganz modular waere es so in etwa
Java:
public class Model {
   private String foo;
   private String bar;
   
   // getter/setter fuer alle Variablen
}

public class FileAccess {
   // lesen und schreiben von Model Objekten
}

public class Application {
   public void start() {
      FileAccess fa = new FileAccess();
      List<Model> models = fa.readModels();
     // was auch immer nun passiert mit denen
     fa.writeModels(models);
  }
}
dann hast du eine schoene Trennung von Model und Logik
 
Und nochmal zu dem String Problem: Angenommen, ich habe ein folgende Klassenhirarchie:
Gefährt > Kraftwagen > PKW > Opel > Astra.
Gefährt > Kraftwagen > LKW
Gefährt > Fahrrad > Pegasus
...

Ist natürlich jetzt übertrieben, aber wenn jede Klasse 2 Instanzvariablen hat, dann ist der Astra Konstruktor ja schon 10 Paramter lang. Umso weiter die Vererbung geht, desto mehr Parameter kommen ja hinzu. Wie soll man da vermeiden zu viele Parameter zu haben?


In Anlehnung an dein obiges Beispiel: Wären meine Modelle dann class Gefaerhrt, class Opel usw?
Und um diese zu sammeln, habe ich eine class Application, die diese in List<Gefaehrt> sammelt und mit ihnen FileAccess aufruft?
 
Alles bis zu einer bestimmten Marke wäre erst einmal abstract und nur der Astra zB direkt instanzierbar.

Gegen übermäßig lange Parameterlisten hilft das Builder Pattern:

Java:
public class Astra extends Opel {
   private Astra(many parameters) {
       //BLA
   }

   public static class Builder {
       public Builder(Some important parameters) {
             //Set those paramters
       }
       public Builder setFieldX(bla) {
           //set it
           return this;
       }
       public Astra build() {
            //If all fields are correctly set:
            return new Astra(feld1, feld2);
           //Else throw exception
      }
   }
   
   //Continue with Astra
}

Das kannst du dann wie folgt aufrufen:

Java:
Astra a = new Astra.Builder("IrgendeinMerkmal", "NochEinMerkmal").setFieldX("gebaut 1999").setFieldY("Nummerschild").build();

Oder auch über mehrere Zeilen verteilt. Das praktischste ist eben, dass du hier in der build() Methode alle Felder überprüfen kannst, ob die im Builder richtig gesetzt wurden und dann rufst du dort den langen Astra Konstruktor auf, ohne, dass der Nutzer der Astra Klasse das tun müsste. Der kann komfortable die sprechenden Setter-Methoden des Builders nutzen. Wichtig ist das
Code:
return this
, damit man diese Verkettung beim Setzen der Werte erreichen kann.
Dabei kann man bei Builder-Objekten auch evtl. das set vor den Settern weglassen. Dort werden ja eh nur Werte gesetzt.

Im Vergleich zu einem Objekt nur mit Settern hat das den Vorteil, dass das Objekt wirklich erst dann genutzt werden kann, wenn es vollständig korrekt initialisiert wurde.
 
Zuletzt bearbeitet:
Danke, das ist wirklich cool und übersichtlich!

Angenommen die Elternklasse Opel hat einen important paremter "motor" und einen optionalen "farbe" im builder. Wie sähe dann meine Astra-Objekterzeugung aus?

Java:
new Astra.Builder("Benzinmotor", "IrgendeinMerkmal", "NochEinMerkmal").setFarbe("pink").setFieldX("gebaut 1999").setFieldY("Nummerschild").build();

So?
 
Jo. Selbstverständlich sind die Beispiele mit "noch ein parameter" und so nicht nötig, aber das wirst du sicher wohl gemerkt haben^^ Praktisch ist auch, wenn die Farbe nicht im Builder gesetzt wird, dann kann der Builder auch eine Standardfarbe definieren (ein Auto ohne Farbe gibts ja nicht). Sodass es tatsächlich auch optionale Sachen geben kann.
Du kannst auch Sachen, die gesetzt werden müssen, in eine der setter-Methoden packen. Dann muss derjenige, der die anwedet natürlich darüber informiert werden, dass die Methode unterlässlich ist.

Im Builderobjekt brauchst du dann natürlich Instanzvariablen, die die Eigenschaften speichern, sollte klar sein^^

Und die Motorarten könnte man besser als Enum deklarieren, aber das schweift ab^^
 

Neue Themen


Zurück
Oben