Rynek nieruchomości a wzorzec fabryka i budowniczy

W tym wpisie opiszę jak zastosować kombinacje dwóch wzorców projektowych do wykorzystania w aplikacji rynku nieruchomości.

Znam trochę osób które interesują się inwestowaniem na rynku nieruchomości. I to mnie zainspirowało do próby stworzenia implementacji wzórców projektowych w kontekście tego zagadnienia. To, co zapewne interesuje potencjalnego intwestora to szybka identyfikacja nieruchomości posiadających duży potencjał. Dlatego tak ważna jest rzetelna informacja dotycząca tychże nieruchomości oraz określenie parametrów świadczących o ich wartości. Powstają już firmy które na podstawie dużej ilości danych starają się przewidzieć faktyczne ceny wykorzystując uczenie maszynowe.

Istotnym problemem jest jednak ustandaryzowanie danych pochodzących z różnych źródeł co w obecnych czasach jest wyzwaniem. Zakładając optymistyczny scenariusz, że takie informacje można pozyskać za pomocą API, można pokusić się o dyskusję jak dokonać abstrakcji obiektów nieruchomości polegając na zewnętrznym API które może ulegać zmianie. Naszym celem jest stworzenie wewnętrznej struktury nieruchomości wykorzystując programowanie obiektowe które będzie czerpać z API. Dla precyzyjnej wyceny nieruchomości potrzebujemy dużej ilości atrybutów ale dla naszego dydaktycznego przykładu skupimy się tylko na kilku.

Najpierw zostaje stworzona klasa symulująca nasz API:

public class simulateProperties {
    public static String simulatePropertyType(String parcelId){
        double checkId= Double.parseDouble(parcelId)%2;
        if (checkId == 1){
            return "House";
        }
        else {
            return "Apartment";
        }
    }
    public static double simulateParcelArea(){
        double parcelarea= Math.random()*10+8;
        return parcelarea;

    }
    public static double simulatePropertyArea(){
        double propertyarea= Math.random()*100+30;
        return propertyarea;

    }
    public static int simulateStorey(){
        Random storey = new Random();
        return storey.nextInt(4);
    }
}

Powyższa klasa posiada metody statyczne które symulują takie parametry jak: rodzaj nieruchomości (Dom bądź mieszkanie, na podstawie numeru nieruchomości wprowadzonego jako parametr), powierzchnię działki (metoda simulateParcelArea), powierzchnię mieszkalną (metoda simulatePropertyArea) oraz piętro (simulateStorey).

Korzystamy z wzorca projektowego fabryka który tworzy odpowiednio różne typy nieruchomości w zależności od parametru określającego jego typ. Ten typ uzyskujemy z naszego symulowanego API. A zatem klasą bazową jest klasa „Property” którą dziedziczą klasy „House” oraz klasa „Apartment”. Klasy te posiadają wspólne metody i obiekty określone w klasie bazowej ale również różnią się pomiędzy sobą. Klasa „House” posiada powierzchnie działki a klasa „Apartment” posiada atrybut piętro. Specyfika tych rodzajów nieruchomości wymaga aby odseparować je od siebie. W naszej aplikacji, klasa fabryka nieruchomości (PropertyFactory), posiada metodę „getProperty” przyjmując argument nr nieruchomości i zwraca odpowiednio dom lub mieszkanie. W klasie Property Factory tworzone są odpowiednio instancje konkretnych nieruchomości za pomocą wzorca Budowniczy.

Najistotniejszym argumentem dla zastosowania wzorca budowniczy a nie konstruktora z dużą liczbą parametrów jest fakt że mamy na uwadzę rozbudowę naszej aplikacji. Przewidujemy że mogą pojawić się nowe atrybuty, jakieś mogą zostać usunięte, dlatego wzorzec budowniczy jest elastycznym a także bardziej estetycznym rozwiązaniem.

Spójrzmy na klasę bazową Property:

public class Property {

protected String parcelNr;
protected double propertyArea;

public String getParcelNr() {
return parcelNr;
}

public double getPropertyArea() {
return propertyArea;
}

public String getPropertyType(){
return "Undefined property.";
}
public void getSummary(){
System.out.println("Nieruchomosc nie zdefiniowana");
}
}

A teraz klasa House:

public class House extends Property {
private String propertyType = "House";
private double parcelArea;

@Override
public String getPropertyType() {
return propertyType;
}

public static class Builder {
private String parcelNr = null;
private double parcelArea = 0;
private double propertyArea = 0;

public Builder parcelNr(String parcelnr){
this.parcelNr=parcelnr;
return this;
}
public Builder parcelArea(double parcelarea){
this.parcelArea = parcelarea;
return this;
}
public Builder propertyArea(double propertyarea){
this.propertyArea = propertyarea;
return this;
}

public House build(){
return new House(this);
}

}
private House(Builder builder){
this.parcelNr = builder.parcelNr;
this.parcelArea = builder.parcelArea;
this.propertyArea = builder.propertyArea;

}

public double getParcelArea() {
return parcelArea;
}

public void getSummary(){
System.out.println("Nieruchomosc typu: "+getPropertyType()+ " ma numer: "+getParcelNr()+" , powierzchnia dzialki: "
+String.format("%.02f", getParcelArea())+" ar, " + "powierzchnia domu: "+String.format("%.02f",
getPropertyArea())+" m2.");
}
}

Powyższa klasa implementuje wzorzec builder poprzez utworzenie klasy statycznej builder wewnątrz posiadającej metody ustawiania zmiennych, ustawiając domyślne wartości na początku klasy. Na końcu dodana jest metoda wyświetlająca podsumowanie.

Analogicznie klasa Apartment:

public class Apartment extends Property {
private String propertyType = "Apartment";
private int storeyNr;

@Override
public String getPropertyType() {
return propertyType;
}

public static class Builder {
private String parcelNr = null;
private double propertyArea = 0;
private int storeyNr = 0;

public Apartment.Builder parcelNr(String parcelnr){
this.parcelNr=parcelnr;
return this;
}
public Apartment.Builder propertyArea(double propertyarea){
this.propertyArea = propertyarea;
return this;
}
public Apartment.Builder storeyNr(int storey){
this.storeyNr = storey;
return this;
}
public Apartment build(){
return new Apartment(this);
}

}
private Apartment(Builder builder){
this.parcelNr = builder.parcelNr;
this.propertyArea = builder.propertyArea;
this.storeyNr= builder.storeyNr;
}

public int getStoreyNr() {
return storeyNr;
}

@Override
public void getSummary() {
System.out.println("Nieruchomosc typu: "+getPropertyType()+ " ma numer: "+getParcelNr()+" , pietro " +getStoreyNr()+
", powierzchnia domu: "+String.format("%.02f", getPropertyArea())+" m2.");
}
}

Poniżej przedstawiona jest klasa fabryki która wykorzystuje api do rozpoznania typu nieruchomości i tworzy odpowiednio obiekty korzystając z metod buildera:

public class PropertyFactory {
    public Property getProperty(String parcelnr) {
        Property property;

        if(simulateProperties.simulatePropertyType(parcelnr).equals("House")){
            property = new House.Builder()
                        .parcelNr(parcelnr)
                .parcelArea(simulateProperties.simulateParcelArea())             .propertyArea(simulateProperties.simulatePropertyArea())
                        .build();
        } else if (simulateProperties.simulatePropertyType(parcelnr).equals("Apartment")){
            property = new Apartment.Builder()
                        .parcelNr(parcelnr)                        .storeyNr(simulateProperties.simulateStorey())                       .propertyArea(simulateProperties.simulatePropertyArea())
                        .build();
        } else {
            property = new Property();
        }
        return property;
    }
}

Należy zwrócić uwagę że kolejność wywołania metod ustawiających zmienne jest dowolna.

Na koniec proste wykonanie programu:

public class Main {

public static void main(String[] args) {
PropertyFactory propertyFactory = new PropertyFactory();
System.out.println("Podaj numer nieruchomosci");
Scanner sc = new Scanner(System.in);
String prop = sc.nextLine();
propertyFactory.getProperty(prop).getSummary();
}
}

Po uruchomieniu w konsoli pojawia się:

Podaj numer nieruchomosci
1410
Nieruchomosc typu: Apartment ma numer: 1410 , pietro 0, powierzchnia domu: 92.55 m2.

A teraz dla innej działki:

Podaj numer nieruchomosci
755
Nieruchomosc typu: House ma numer: 755 , powierzchnia dzialki: 14.03 ar, powierzchnia domu: 84.08 m2.

Ten przykład pokazuje jak za pomocą niewielkiej ilości kodu stworzyć elastyczną aplikację umożliwiającą rozszerzenie funkcjonalności poprzez łatwe dodanie nowych rodzajów nieruchomości oraz dodatnie nowych atrybutów nieruchomości. Oprócz tego, korzystając z luźnego powiązania z klasą łączącą się z API jesteśmy w stanie szybko i efektywnie aktualizować samą klasę bez wpływu na naszą „Fabrykę nieruchomości”

Rynek nieruchomości a wzorzec fabryka i budowniczy

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *