OOP Factory Muster ausbauen

Meeresgott

Bekanntes Mitglied
Hallo liebes Forum,

ich sitzt zurzeit an einer Änderung in meinem Code.

Ich benutze das Factroy Muster um verschiedene "Häuser" zu generieren. Jede variante (Villa, Reihenhaus, Landhaus etc. alle erben von Haus)
Die Klasse HaueserFactory hat die Methode:
+ Haus getInstance(HaeuserTyp typ)
wobei HaeuserTyp ein enum ist. (Mit den oben genanten Objekten Villa usw.)

Jeder Haus-Typ hat unterschiedliche m^2, Fensteranzahl sowie Zimmeranzahl, Fensteranzahl usw.
Wenn ich jetzt ein Häusertyp ändern möchte z.B. die Quadratmeter Zahl für das Haus mit dem Typ "Villa" muss ich die Klasse ändern also in dem Code Änderungen vornehmen.

Das will ich vermeiden!

Ich habe zwei Ansätze:

Ich füge in der Klasse ein statisches Objekt vom Typ "Property" hinzu. Statisch damit jede Unterklasse dasselbe Objekt nutzt und nicht alle ein neues Objekt vom Typ Property besitzt.
Dann lade ich die spezifischen Eigenschaften in die Unterklassen.

Java:
public class Haus
{
       static Property prop = null;

      public Haus()
      {
            if(prop = null)
                 prop = new Property();
                  //Hier der PropertyLadecode
      }
     //Hier noch weiterer Haus Code
}

Java:
public class Villa extends Haus
{
     public Villa()
     {
          String m2 = super.prop.getProperty("villa.m2");
          String fenster = super.prop.getProperty("villa.fenster");
          //usw.
     }
}
mir viel grade auf, dass es mehr Sinn machen würde das laden des Property Objektes auszulagern aber ist auch erstmal ein erster Entwurf.
Dann mein zweiter Ansatz den ich persönlich interessanter finde allerdings fehlt mir hier der Ansatz zur Umsetzung:

Bislang hat jeder Haus Typ seine eigene Klasse wenn ich Ansatz 1 umsetzte unterscheiden sich die Häuserunterklassen nur von dem "<HausTyp>.m2" Aufruf bei den Properties.
Wenn ich jetzt hin gehe und die Haus-Klasse umschreibe sodass es möglich ist den HausTyp über den Konstrukor zu übergeben und dass haus darauf hin die zum Haustyp gehörigen Variablen lädt, habe ich nur noch die Haus klasse und wenn ich ein Haus hinzufügen möchte muss ich nur ein neuen Haustyp hinzufügen und in die Default Properties die neuen Variablen ergänzen. Quasi muss ich den Code kaum noch anfassen.

Die Umsetzung wirft allerdings ein paar Fragen auf:

- Macht der Ansatz überhaupt erst Sinn? Eine Klasse für alle Häuser?
- Wie füge ich am besten alles ein?
- Macht es überhaupt noch Sinn für die HausTypen enum zu verwenden ? Wie könnte ich dies am besten ersetzten, dass ich nur durch ändern von config bzw. properties ein Haus hinzufügen kann ?

Für die Antworten danke ich im Voraus! :)

lg,
Meeresgott
 

AndyJ

Bekanntes Mitglied
Ist ein etwas seltsamer UseCase (ich dachte nicht dass jede Villa genau gleich gross ist), aber der folgende Ansatz koennte funktionieren:

Dein enum bestimmt bestimmte Eigenschaften:
Code:
package info.junius.test;

public enum HausTyp {

  VILLA(350, 6, 12),
  REIHENHAUS(120, 3, 5);

  private final int groesse;
  private final int zimmer;
  private final int fenster;

  private HausTyp(int groesse, int zimmer, int fenster) {
  this.groesse = groesse;
  this.zimmer = zimmer;
  this.fenster = fenster;
  }

  public int getGroesse() {
  return this.groesse;
  }

  public int getZimmer() {
  return this.zimmer;
  }

  public int getFenster() {
  return this.fenster;
  }
}

Die Klasse Haus ist immutable, sprich kann nachtraeglich nicht veraendert werden:
Code:
package info.junius.test;

public class Haus {
  private final HausTyp hausTyp;

  public Haus(HausTyp hausTyp) {
  super();
  this.hausTyp = hausTyp;
  }

  public int getGroesse() {
  return this.hausTyp.getGroesse();
  }

  public int getZimmer() {
  return this.hausTyp.getZimmer();
  }

  public int getFenster() {
  return this.hausTyp.getFenster();
  }

  /* (non-Javadoc)
  * @see java.lang.Object#toString()
  */
  @Override
  public String toString() {
  return String.format("Haus [hausTyp=%s, getGroesse()=%s, getZimmer()=%s, getFenster()=%s]",
  this.hausTyp,
  this.getGroesse(),
  this.getZimmer(),
  this.getFenster());
  }

}

Erstellen kann man dann eine Instance von einem Haus wie folgt:
Code:
Haus villa = new Haus(HausTyp.VILLA);
System.out.println(villa);

Prints:
Haus [hausTyp=VILLA, getGroesse()=350, getZimmer()=6, getFenster()=12]

Cheers,
Andy
 

nvidia

Bekanntes Mitglied
Das kann man so machen, diese Art des des Designs stellt die Daten in den Vordergrund. Persönlich würde ich wohl keine Properties verwenden sondern eine eigene typisierte Klasse Attribute<A> damit man nicht mit Strings hantieren muss. Die Idee welche du beschreibst geht in die Richtung Entity Component System. Grob gesprochen ist dort ein Objekt bzw. Component ein relativ dummes Datenobjekt bestehend aus Attributen und einer eindeutigen ID. Ein System ist die verarbeitende Einheit die anhand der vorhandenen Attribute entscheidet wie das Datenobjekt verarbeitet werden soll. Ein wenig googlen sollte die entsprechenden Ressourcen hervorbringen.
 

Jardcore

Top Contributor
Was ich mich frage ist, was möchtest du eigentlich erreichen? Was ist dein UseCase?

Das Factory Pattern funktioniert allgemein so:

Java:
public class ShapeFactory{
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }     
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
       
      }else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
       
      }else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}
Man könnte hier auch die Methode getShape static machen um keine Instanz von der ShapeFactory erzeugen zu müssen.
Weiterhin kann man die Abfrage Statt durch einen String, wie von dir überlegt, durch ein Enum realisieren und dann mit einem einfachen Switch Case arbeiten.

Dir Factory soll dir aber nur ein Objekt liefern, Werte kannst du danach zuweisen. Einfache Initialisierungen kannst du, wie bereits erwähnt, durch Variablen im Enum realisieren.
 

Meeresgott

Bekanntes Mitglied
Guten Tag,

erstmal zu dem "merkwürdigen" UseCase, dieser ist nur ein Beispiel mit dem ich zurzeit arbeite. Natürlich hat nicht jede Villa die selben Quadratmeter. Ich wollte nur erstmal für mich das Problem lösen mit einer simpleren Anwendung um die Lösung später in meinen eigentlichen Code zu übertragen.

Dir Factory soll dir aber nur ein Objekt liefern, Werte kannst du danach zuweisen. Einfache Initialisierungen kannst du, wie bereits erwähnt, durch Variablen im Enum realisieren.

Meine HausTypen brauchen ja gewisse Grundwerte und geben somit ein "halb fertiges" Objekt zurück. Also denkst du, dass ich das Factory-Muster nicht benutzen sollte?

@AndyJ
Dein Vorschlag ist sehr vielversprechend und wahrscheinlich sogar der bessere Ansatz.

lg
 

mrBrown

Super-Moderator
Mitarbeiter
Ist denn der Typ außer für die unterschiedlichen Parameter relevant?

Ich persönlich würde nicht die Variante mit Enums nutzen, außer für den Haustyp (uU default-Werten für diesen). Nutzt du enums zum halten der Attribute, kannst du diese nicht mehr ändern, und wie du selbst sagst, haben nicht alle Häuser eines Types die gleichen Werte.


Und um noch mal 'nen dritten Vorschlag zu machen: Builder-Pattern :p
mit statischer Methode, die den Haustyp bekommt (und uU im Builder default-Werte setzt) und dann zusätzlichen Settern für alle Attribute. Kannst dann sowohl die Default-Werte aus enums nutzen, kannst aber auch alles anpassen.
 

Jardcore

Top Contributor
Meine HausTypen brauchen ja gewisse Grundwerte und geben somit ein "halb fertiges" Objekt zurück. Also denkst du, dass ich das Factory-Muster nicht benutzen sollte?
Ja, ich denke das Builder-Pattern welches mrBrown hier vorschlägt wäre besser geeignet. Vielleicht aber auch eine Mischung aus beiden^^
Java:
public class VillaBuilder implements HausProperties<VillaBuilder> {
    private int groesse;
    private List<Zimmer> zimmer;
    // weitere Attribute

    @Override
    public VillaBuilder setGroesse(int groesse) {
         this.groesse = groesse;
    }

    // usw. addZimmer

    public Villa create() {
        Villa villa = new Villa();
        villa.setGroesse(groesse);
        villa.addZimmer(zimmer);
        return villa;
    }
}

Java:
public interface HausProperties<T> {
    public T setType(HausType type);
    public T setGroesse(int groesse);
    public T addZimmer(Zimmer zimmer);
}

Oder gleich den HausBuilder

Java:
public class HausBuilder implements HausProperties<HausBuilder> {
    private HausTyp type;
    private int groesse;
    private List<Zimmer> zimmer;
    // weitere Attribute

    @Override
    public HausBuilder setType(HausType type) {
        this.type = type;
    }
    @Override
    public HausBuilder setGroesse(int groesse) {
         this.groesse = groesse;
    }

    public Haus create() {
        Haus haus = HausFactory.getHaus(type);
        haus.setGroesse(groesse);
        haus.addZimmer(zimmer);
        return haus;
    }
}
 
Zuletzt bearbeitet:

Flown

Administrator
Mitarbeiter
@Jardcore Ich finde das Builder-Pattern sollte von dir etwas angepasst werden (Alle Methoden in Interfaces sind implizit public, darum kann man das getrost weglassen):
Java:
public interface HausBuilder<T extends Haus> {
  HausProperties<T> setType(HausType type);
  HausProperties<T> setGroesse(int groesse);
  HausProperties<T> addZimmer(Zimmer zimmer);
  T build();
}
Eine build (oder create) Methode darf in einem Builder nicht fehlen. Der return type sollte auch angepasst werden.
 

Meeresgott

Bekanntes Mitglied
Danke! Hat zwar bis grade gedauert alles wie gewünscht um zusetzten aber es funktioniert tadellos.

Wäre es eigentlich "Muster-Konform" wenn ich sowas machen würde:

Code:
public class HausBuilder implements HausProperties<HausBuilder>
{
    private HausTyp type;
    private int groesse;
    private List<Zimmer> zimmer;
    private static Properties prop;
    // weitere Attribute

    @Override
    public HausBuilder setType(HausTyp type) {
        this.type = type;
        this.groesse = Integer.valueOf( prop.getProperty(type.name()+".groesse") );
        return this;
    }
    //weitere Code
}

Dann habe ich noch ein Problem bei der Umsetzung vom dem Vorschlag von @Flown wenn ich
T durch T extends Haus und T build() hinzufüge was muss ich dann in der Klasse Hausbuilder ändern damit der Compiler die Veränderung annimt ?

Ändere ich die Klasse wie folgt funktioniert alles:
Java:
public interface HausProperties<T> {
    public T setType(HausTyp type);
    public T setGroesse(int groesse);
    public T addZimmer(Zimmer zimmer);
    Haus build();
}
Wenn ich <T extends Haus> einsetzte bekomme ich einen konflickt, die Methode setGroesse(int g) von Haus keinen rückgabetyp hat (void) und die Methode von HausBuilder hat einen (HausBuilder)
lg
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Benenn das HausProperties mal lieber in HausBuilder. Das ist das Interface für den Builder, nicht für Builder und Haus ;)

Das Interface sollte so aussehen wie von @Flown gezeigt (bis auf den Rückgabetyp, der muss HausBuilder<T> und nicht HausProperties<T> sein).
 

Thallius

Top Contributor
Was für einen Sinn macht es überhaupt den Haustyp als enum zu deklarieren? Wo brauchst du den typ als Zahl? Mach ihn doch einfach als einfaches Atttribut String und gut ist. Wozu der ganze Factory Kram? Macht es doch nur unnötig kompliziert. Du hast eine Klassse Haus mit den Attributen Typ, qm, Zimmer, etc. Die befüllst du dann entsprechend.
 

mrBrown

Super-Moderator
Mitarbeiter
Was für einen Sinn macht es überhaupt den Haustyp als enum zu deklarieren? Wo brauchst du den typ als Zahl? Mach ihn doch einfach als einfaches Atttribut String und gut ist.
Enum ist eben keine Zahl und auch kein String.
Bei einer fest definierten Menge von Werten machen Enums schon Sinn, man verliert mit denen nichts, was Strings oder Integer böten, gewinnt aber Typsicherheit und kann denen zusätzlich auch noch Attribute mitgegeben.

Wozu der ganze Factory Kram? Macht es doch nur unnötig kompliziert. Du hast eine Klassse Haus mit den Attributen Typ, qm, Zimmer, etc. Die befüllst du dann entsprechend.
MMn machts das eher einfacher als komplizierter...

Man erzeugt alle Objekte über gleich (statt für jede Klasse eigenen Konstruktor) und hat das an eine Stelle ausgelagert
Kann mit Defaultwerten arbeiten, kann aber auch jeden einzeln setzen und hat trotzdem immer ein vollständiges Objekt, ohne 17 überladene Konstruktoren zu haben
Mehr Aufwand ists nicht wirklich, sind gefühlt 3 Klicks in der IDE und 90% sind fertig...
 

Thallius

Top Contributor
Enum ist eben keine Zahl und auch kein String.
Bei einer fest definierten Menge von Werten machen Enums schon Sinn, man verliert mit denen nichts, was Strings oder Integer böten, gewinnt aber Typsicherheit und kann denen zusätzlich auch noch Attribute mitgegeben.


MMn machts das eher einfacher als komplizierter...

Man erzeugt alle Objekte über gleich (statt für jede Klasse eigenen Konstruktor) und hat das an eine Stelle ausgelagert
Kann mit Defaultwerten arbeiten, kann aber auch jeden einzeln setzen und hat trotzdem immer ein vollständiges Objekt, ohne 17 überladene Konstruktoren zu haben
Mehr Aufwand ists nicht wirklich, sind gefühlt 3 Klicks in der IDE und 90% sind fertig...

Kapier ich nicht. Was in an einer Klasse mit einem Konstruktor

public Haus (String type, int qm, int zimmer)

denn jetzt komplizierter als mit irgendwelchen überladenen Klassen zu arbeiten?

Und mit den enum beschränkst du dich halt im code. Sprich neue Haustypen gibt es nur mit neuer Software. Warum das ? MAche ich den Typ als String kann ich jederzeit beliebig neue Typen hinzufügen und mein Code ändert sich nicht.
 

mrBrown

Super-Moderator
Mitarbeiter
Kapier ich nicht. Was in an einer Klasse mit einem Konstruktor

public Haus (String type, int qm, int zimmer)

denn jetzt komplizierter als mit irgendwelchen überladenen Klassen zu arbeiten?
Haus hat 17 Attribute, ich möchte nur die Zimmerzahl ändern, und bei allen anderen Defaultwerte nutzen.

Builder: ein Setter-Aufruf
Ohne Builder: Entweder hab ich nach dem Konstruktor kein fertiges Objekt, oder man braucht unzählige überladene Konstruktoren, oder muss immer alle Werte übergeben. Keins davon will man.

Und mit den enum beschränkst du dich halt im code. Sprich neue Haustypen gibt es nur mit neuer Software. Warum das ? MAche ich den Typ als String kann ich jederzeit beliebig neue Typen hinzufügen und mein Code ändert sich nicht.
Bei der Ursprungsfrage ist sowieso jeder Typ eine eigene Klasse, der Code müsste also sowieso geändert werden.
Fürs einfache Erweitern um weitere Typen müsste man sowieso noch mehr anpassen.
Da wäre mir persönlich erstmal Typsicherheit und die Attribute wichtiger, Fehler macht man immer, so hat man eine mögliche Quelle weniger. ViIla statt Villa übersieht man schnell mal...
 

Thallius

Top Contributor
Haus hat 17 Attribute, ich möchte nur die Zimmerzahl ändern, und bei allen anderen Defaultwerte nutzen.

Builder: ein Setter-Aufruf
Ohne Builder: Entweder hab ich nach dem Konstruktor kein fertiges Objekt, oder man braucht unzählige überladene Konstruktoren, oder muss immer alle Werte übergeben. Keins davon will man.

Ist mir zu hoch...

Mache ich halt eine Klasse

Code:
public class Haus
{
    private String typ = "Villa";
    private int qm = 100;
    private int zimmer = 2;
    ....

    public Haus()
    {
    }

    public void setZimmer(int z)
    {
        zimmer = z;
    }

     ... weitere Setter und Getter
}

Wo brauche ich jetzt undendlich viele Konstruktoren?

Code:
Haus haus = new Haus();
haus.setZimmer(20);

fertig.

Zur Absicherung des Typ als String mache ich eine XML Datei mit allen erlaubten Typen. Beim Erstellen vergleiche ich damit. Brauche ich einen neuen Typ, ergänze ich diesen in der XML Datei. Kein neuer Code notwendig...
 

mrBrown

Super-Moderator
Mitarbeiter
Außerdem:
Java:
Haus haus = new Haus();
haus.setZimmer(20);
Hat man solchen Code öfters, uU noch mit mehreren Settern, landet man irgendwann unweigerlich beim Refactoring, lagert das in eine eigene Methode aus, merkt das es viel besser in eine Klasse passt, und schon ist man beim Builder.
 

Meeresgott

Bekanntes Mitglied
Ich finde das Build-Pattern das richtige ist. Ich benutze enum damit ich die Default werte damit übertragen kann wenn sich etwas ändert muss ich nur din Enums verändern.
Ich benutze extra ein Muster damit, wie von @mrBrown erwähnt nicht alles mit setter setzten muss. Das Haus ist auch nur ein Beispiel. In meinem eigentlich Programm hätte ich mehrere Hundert HausTypen und da würde ich gerne das ewige Set vermeiden und schonmal mit den Enums die werte übergeben die sich nicht ändern und später dann mit ein paar wenigen settern das Objekt fertig stellen kann.

@mrBrown Ich Poste heute Abend den Code der Klassen mit deinen Veränderungen. Hoffe ich habe alles verstanden mit den Änderungen.
 

mrBrown

Super-Moderator
Mitarbeiter
In meinem eigentlich Programm hätte ich mehrere Hundert HausTypen und da würde ich gerne das ewige Set vermeiden und schonmal mit den Enums die werte übergeben die sich nicht ändern und später dann mit ein paar wenigen settern das Objekt fertig stellen kann.
Bei mehreren hundert Typen würde ich übrigens weder Enums noch eigene Klassen für alle nutzen, sondern das in externe properties/json/xml auslagern.
Dazu eine eigene Typ-Klasse, in die das direkt geparsed wird, und das ganze in eine Map die String mit Typname auf Typ-Objekt mappt.
Kommt da wieder ein Interface drüber, kann man erstmal bei den Enums bleiben, und später wechseln.
 

Meeresgott

Bekanntes Mitglied
So habe mir deinen Vorschlag mit den Properties zu herzen genommen.
So wie ich euch verstanden habe sieht die Realisierung so aus:

Das Interface:
Java:
public interface AbstraktHausBuilder<T> {
    public T setType(String type);
    public T setGroesse(int groesse);
    public T setLocation(int x,int y);
    public T setFenster(int fenster);
    public Haus build();
}

Der kronkrete Builder:
Java:
public class KonkreterHausBuilder implements AbstraktHausBuilder<KonkreterHausBuilder>
{
   
    private static Properties prop = LoadProperties.getProperties();
   
    private String type;
    private int groesse;
    private int xLocation;
    private int yLocation;
    private int fenster;
   
    @Override
    public KonkreterHausBuilder setType(String type)
    {
        this.type    = type;
        this.groesse = Integer.valueOf(prop.getProperty(type+".groesse"));
        this.fenster = Integer.valueOf(prop.getProperty(type+".fenster"));
        return this;
    }

    @Override
    public KonkreterHausBuilder setGroesse(int groesse) {
        this.groesse = groesse;
        return this;
    }

    @Override
    public KonkreterHausBuilder setLocation(int x, int y)
    {
        xLocation = x;
        yLocation = y;
        return this;
    }
   
    @Override
    public KonkreterHausBuilder setFenster(int fenster)
    {
        this.fenster = fenster;
        return this;
    }

    @Override
    public Haus build()
    {
        Haus haus = new Haus();
        haus.setFenster(fenster);
        haus.setType(type);
        haus.setxLocation(xLocation);
        haus.setyLocation(yLocation);
        haus.setGroesse(groesse);
        return haus;
    }
}

Der Haus Code:
Java:
public class HausClient
{
    public static void main (String[] args)
    {
        Haus villa = new KonkreterHausBuilder()
                          .setType("villa")
                          .setLocation(7, 10)
                          .build();
       
        System.out.println("Villa: "+villa.toString());
    }
}

und falls noch relevant die Properties-Datei:
Code:
#HausTypes
#Thu Sep 08 14:35:39 CEST 2016
villa.name=villa
villa.fenster=4
villa.groesse=10

Klappt soweit schon mal sehr gut. Nur habe ich jetzt, ohne Enums das Problem das ich nicht kontrollieren
kann ob es diesen HausTyp überhaupt gibt. Ich könnte jetzt statt "villa" auch "gartenhaus" schreiben, dies würde allerdings zu einer Exception führen.

Ich habe keine Map verwendet, da ich nicht weiß wie ich an die Keys (HausTypen) komme.
Der Punkt deshalb habe ich die Property "villa.name" hinzugefügt. Meine einzige Idee wäre um an die Keys zu kommen mir von Property alle Keys zu geben jeden Key auf ".name" prüfen und wenn ein Key .name vorhanden ist dann mir von Property die Value zu dem Key zu geben.

Hat jemand eine bessere Idee ?
 

mrBrown

Super-Moderator
Mitarbeiter
Gibt es nur eine Haus-Klasse oder verschiedene Implementierungen von Haus? (Und falls ja, gilt Typ<=>Klasse?)
 

Meeresgott

Bekanntes Mitglied
Stimmt ich habe ganz vergessen den Haus Code zu posten.
So wie ich euch verstanden habe, sollte ich nur eine Haus-Klasse benutzen.

Hier wäre der Code für die Haus Klasse den ich benutze:
Java:
public class Haus
{
    private String type;
    private int groesse;
    private int xLocation;
    private int yLocation;
    private int fenster;

    public void setFenster(int fenster)
    {
        this.fenster = fenster;
    }
   
    public void setType(String type) {
        this.type = type;
    }

    public void setGroesse(int groesse) {
        this.groesse = groesse;
    }

    public void setxLocation(int xLocation) {
        this.xLocation = xLocation;
    }

    public void setyLocation(int yLocation) {
        this.yLocation = yLocation;
    }

    @Override
    public String toString() {
        return "Haus{" + "type=" + type + ", groesse=" + groesse + ", xLocation=" + xLocation + ", yLocation=" + yLocation + ", fenster=" + fenster + '}';
    }
}
 

mrBrown

Super-Moderator
Mitarbeiter
Den generischen Parameter kannst du dir sparen, und stattdessen immer AbstraktHausBuilder zurückgeben.

Der kronkrete Builder:
Die properties für alle Typen würde ich in einem eigenem Objekt Kapseln, worin dann auch schon die Werte passend geparsed werden.
Die properties jeweils eines Types würde ich auch wieder kapseln. Der Builder fragt dann nur noch die Default-Werte ab, die Quelle dieser ist für diesen ja erstmal egal.

Ich würde auch dem Konstruktor schon den type übergeben, einerseits hat man dann direkt die Defaultwerte initialisiert, andererseits spart man sich einen Setteraufruf.

Klappt soweit schon mal sehr gut. Nur habe ich jetzt, ohne Enums das Problem das ich nicht kontrollieren
kann ob es diesen HausTyp überhaupt gibt. Ich könnte jetzt statt "villa" auch "gartenhaus" schreiben, dies würde allerdings zu einer Exception führen.
In dem Fall wäre Exception auch das passende ;) Kann man eine eigene schrieben und dann werfen

Ich habe keine Map verwendet, da ich nicht weiß wie ich an die Keys (HausTypen) komme.
Der Punkt deshalb habe ich die Property "villa.name" hinzugefügt. Meine einzige Idee wäre um an die Keys zu kommen mir von Property alle Keys zu geben jeden Key auf ".name" prüfen und wenn ein Key .name vorhanden ist dann mir von Property die Value zu dem Key zu geben.

Musst du an die Keys kommen?
Ob ein Key existiert kannst du mit contains prüfen (wird natürlich mit ".name" etc komplexer, deshalb würde ich das in einem Objekt kapseln)
 

Meeresgott

Bekanntes Mitglied
Ich habe soweit alles verstanden und umsetzten können. Habe aber noch eine Frage zu den Properties
Du hast mir vorgeschlagen die Variablen/Properties eines Types zu kapseln und die von allen Properties ebenfalls.

Das hätte ich dann so verstanden:
Java:
public class HausValues
{
    String name;
    int groesse;
    int fenster;

    public HausValues(String type, int groesse, int fenster) {
        this.name = type;
        this.groesse = groesse;
        this.fenster = fenster;
    }
}

Java:
public class HausTypProperties
{
    private static Properties prop = LoadProperties.getProperties();
   
    private static final String PREFIX_NAME    = ".name";
    private static final String PREFIX_FENSTER = ".fenster";
    private static final String PREFIX_GROESSE = ".groesse";
   
    public static HausValues getHausValues(String type) throws HausNotFoundException
    {
        if(prop.containsKey(type+".name"))
        {
            HausValues values = new HausValues();
            values.fenster = Integer.valueOf(prop.getProperty(type+PREFIX_FENSTER));
            values.groesse = Integer.valueOf(prop.getProperty(type+PREFIX_GROESSE));
            values.name    = prop.getProperty(type+PREFIX_NAME);
            return values;
        }
        throw new HausNotFoundException(type);
    }
}

Ich habe eine "HausValues"-Klasse und eine HausTypProperties. Der HausTypProperties Klasse übergebe ich den HausType und erhalte die dementsprechenden HausValues zurück. Dieser Methode wird im Konstruktor der Klasse KonkreterHausBuilder aufgerufen.

Java:
public class KonkreterHausBuilder implements AbstraktHausBuilder
{
    private String type;
    private int xLocation;
    private int yLocation;
    private HausValues values;
    
    public KonkreterHausBuilder(String type) throws HausNotFoundException
    {
        this.type = type;
        values = HausTypProperties.getHausValues(type);
    }
   
    Override
    public KonkreterHausBuilder setType(String type) throws HausNotFoundException
    {
        values = HausTypProperties.getHausValues(type);
        this.type    = type;
        return this;
    }

     //Hier zwischen hat sich nichts verändert
     //Außer das Setter statt z.B. 
     //this.groesse = groesse
     //values.groesse = groesse

    @Override
    public Haus build()
    {
        Haus haus = new Haus();
        haus.setFenster(values.fenster);
        haus.setGroesse(values.groesse);
        //Sonst hat sich nichts verändert
        return haus;
    }
}

Da setType(String) jetzt eine Exception werfen kann habe ich diese auch schon im Interface hinzugefügt.

Java:
public interface AbstraktHausBuilder {
    public AbstraktHausBuilder setType(String type) throws HausNotFoundException;
    //Rest ist auch hier gleich geblieben.
}

Hoffe ich habe dich richtig verstanden.

lg
 

Meeresgott

Bekanntes Mitglied
Und der Vollständigkeit halber:
hier noch die HausNotFoundException.

Code:
public class HausNotFoundException extends Exception
{
    public HausNotFoundException(String type)
    {
        super("Fail! HausType "+type+" konnte nicht gefunden werden.");
    }
}
 

mrBrown

Super-Moderator
Mitarbeiter
Den Builder hätte ich mit seinen Attributen so gelassen, und deine HausValues nur zum Setzten von Defaultwerten genutzt, dann muss man die auch nur einmalig aus den properties parsen und kann sie immutable machen.

Die Exception würde ich RuntimeException extenden lassen, und nicht Exception, dann sparst du dir die throws-Deklaration (ganz grob: wenn der Grund ein Programmierfehler ist, dann RuntimeException, wenns am Nutzer liegt Exception)


Aber ja, geht in die Richtung die ich meinte ;)
 

Meeresgott

Bekanntes Mitglied
dann muss man die auch nur einmalig aus den properties parsen und kann sie immutable machen.

Wenn ich die Atribute groesse;int und fenster;int immutable mache, muss ich logischerweise die Methode setType(String) aus dem Interface nehmen.
Macht auch mehr Sinn, da der HausType und die damit zusammenhängenden Attribute nicht verändert werden sollen.
Kann im Interface den Konstrukor ja nicht vorgeben. Also ist es mir auch nicht mehr möglich einem Child von AbstraktHausBuilder das Laden des Types "aufzuzwingen".
Ist zwar nur eine Kleinichkeit und vielleicht auch nicht wichtig. Ich möchte nur wissen ob das "OK" ist es so um zusetzten.

Sonst habe ich den KonkretenBuilder seine alten Attribute zurückgegeben und die Exception ist jetzt eine Erweiterung von RunetimeException :)
Gut hatte schon Sorge, dass ich mit meiner Umsetztung auf dem Holz weg bin ;)
 

mrBrown

Super-Moderator
Mitarbeiter
Wenn ich die Atribute groesse;int und fenster;int immutable mache, muss ich logischerweise die Methode setType(String) aus dem Interface nehmen.
Im Builder muss nichts final sein, den Setter kann man da drin lassen. Ich meinte HausValues nur mit Gettern und ohne Setter ;)


Gut hatte schon Sorge, dass ich mit meiner Umsetztung auf dem Holz weg bin

Ob's das beste ist weiß ich nicht, wäre nur meine Unsetzung ;)
Siehst ja weiter oben schon, dass es da viele Meinungen zu gibt
 

Meeresgott

Bekanntes Mitglied
Ah okay dann waren meine Bedenken also richtig ;)

Ich finde die Lösung auf jeden Fall super ! Sie hat alles schön gekapselt und bedient sich eines OO-Musters.
Muss mich da selber noch echt reinfuchsen, habe die Muster nicht so gut drauf und gemerkt wie wichtig sie doch sind :)

Allerdings hätte ich noch eine Frage:
Meine Klasse HausTypProperties mit der statischen Methode getHausValues(String) ;HausValues
Erinnert mich zumindest stark an das Factory-Muster (nur das der RückgabeTyp kein Child von HausValues ist, sondern eine fertig konfiguriertes HausValues-Objekt).
Wäre meine HausTypProperties-Klasse nicht eher eine HausValuesFactory-Klasse?
 

mrBrown

Super-Moderator
Mitarbeiter
Meine Klasse HausTypProperties mit der statischen Methode getHausValues(String) ;HausValues
Erinnert mich zumindest stark an das Factory-Muster (nur das der RückgabeTyp kein Child von HausValues ist, sondern eine fertig konfiguriertes HausValues-Objekt).
Wäre meine HausTypProperties-Klasse nicht eher eine HausValuesFactory-Klasse?
Ich würde auch daraus Interface + Implementierung mache, das wäre dann keine Factory (wobei es dann dafür eine Factory geben könnte :p)
 

Meeresgott

Bekanntes Mitglied
Ich glaube ich übernehme noch das mit der Implementierung aber werde dann keine HausTypPropertiesFactory einbauen.

Ich merke man kann hier auch an Schönheit sterben ;)

Ich danke für deine Hilfe :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
Meeresgott Best Practice "Spezifisches" Factory Pattern ? Allgemeine Java-Themen 1
K Factory Pattern: Mit Generics umgehen Allgemeine Java-Themen 6
M Wo hin mit static factory methods? Allgemeine Java-Themen 40
M Factory Allgemeine Java-Themen 14
T Klassen Fabrik (Factory) zur Laufzeit erweitern Allgemeine Java-Themen 5
Luk10 Factory auf meine Situaion anwendbar? Allgemeine Java-Themen 14
M Eigene Factory Klasse Allgemeine Java-Themen 21
T So eine Art Singleton-Factory? Allgemeine Java-Themen 3
S Designproblem: Factory organisieren Allgemeine Java-Themen 4
EagleEye erstellen ein factory Allgemeine Java-Themen 13
I Muster in Array suchen Allgemeine Java-Themen 10
M Alles außer Muster in String ersetzen Allgemeine Java-Themen 1
W String Parsen und auf eigenes Muster anwenden (kein Regex) Allgemeine Java-Themen 11
B Muster in 2D-Array finden Allgemeine Java-Themen 4
L Strings nach gleichem Muster ordnen Allgemeine Java-Themen 4
G ThreadLocal in Muster "Unit of Work" Allgemeine Java-Themen 7
D Sterne Muster mit einer Schleife Allgemeine Java-Themen 5
K ArrayList nach bestimmtem Muster sortieren Allgemeine Java-Themen 3
S Kompositum Muster ohne Exception oder instanceof Operator Allgemeine Java-Themen 6
M RegEx: Muster ersetzen Allgemeine Java-Themen 6
T Muster/Zeichen/Texterkennung auf einem Image Allgemeine Java-Themen 9
G String nach Muster durchsuchen Allgemeine Java-Themen 5
X Bestimmtes Muster in Textdatei verändern Allgemeine Java-Themen 13
K Sequenzdiagramm für Singleton-Muster Allgemeine Java-Themen 5
M Rekursiv Verzeichnisse ansehen und auf Muster matchen Allgemeine Java-Themen 6
F Login einfach "ausbauen" Allgemeine Java-Themen 10

Ähnliche Java Themen

Neue Themen


Oben