Kiedy stosować Factory a kiedy Mother?

0

Załóżmy, że mam skomplikowanego mapera do wstrzyknięcia do jakiejś metody/konstruktora:

interface MyMapper <T>extends Function<String, T> {

}

lepiej tworzyć go tak:

class MyMapperMother implements MyMapper<Integer> {

    private int multiplyBy;

    public MyMapperMother (int multiplyBy) {
         this.multiplyBy = multiplyBy;
    }

    @Override
    public Integer apply() {
        // ...
        // ... skomplikowana implementacja
        // ...
        return result * multiplyBy;
    }
}

i przekazywać tak:

// ...
builder.setMapper(new MyMapperMother(12)) 
// ...

czy tworzyć tak:

class MyMapperFactory {

    public MyMapper<String, Integer> produceMapper(int multiplyBy) {
        return x -> {
            // ...
           // ... skompliokwana implementacja
           // ...
           result * multiplyBy;
         }
    }
}

i przekazywać tak:

// ...
builder.setMapper(new MyMapperFactory.produceMapper(12)) 
// ...
1

Lepsza jest druga opcja IMHO. Dzięki fabryce ukryjesz klasę i będziesz operować na samym interfejsie co może przynieść korzyść przy podmianie implementacji w przyszłości.

2

produceMapper brzmi co najmniej dziwnie i sugeruje ze tworzysz jednego mappera przy użyciu factory? Po co? Ta klasa wygląda jak słaba krzyżówka 2 patternów - abstract factory/factory"class" i factory method. Porównujesz 2 podejścia, które nie rozwiązują tego samego problemu. Wchodząc prosto w over engineering.

Jeżeli chcesz to w czysty sposób zrobić to wg mnie możesz do tego podejść:

  1. Używając factory method czyli - MyMapperMother.of(12) - statyczna metoda zwracająca instancje - czyste, krótkie, przyjemne dla oka
  2. No ta wersja z konstruktorem.
  3. Jeżeli masz kilka mapperów lub spokrewnionych obiektów to factory class jest ok, tylko wtedy pytanie, dlaczego to factory miałoby mieć instancje ? Dlaczego wszystkie z factory method w factory nie miałby być statyczne? -
    MyMapperFactory.produceMotherMapper(12)
    MyMapperFactory.produceFatherMapper(12)

Hmm i tam chyba, funkcja apply powinna mieć jakiś argument nie? String jak dobrze patrze.
Edit: I dlaczego setMapper nie może przyjmować Function<String,T> tylko musi mieć rozszerzony interface? Czy to jest po to zeby generyk wyglądał ładnie czy faktycznie będzie zawierał jakieś wspólne metody? Bo jak nie bedzie zawierał tak owych, to nie będzie potrzebna hierarchia ---> nie będzie potrzebna factory class.
Edit2: I jeżeli to jest faktycznie builder to wyrzuć to ohydne setMapper i daj po prostu mapper(...) :DD

0

dzięki za opinie,

Interpod napisał(a):

Dlaczego wszystkie z factory method w factory nie miałby być statyczne? -

chciałem zrobić statyczne, ale wtedy się nie da dołożyć interfejsu z abstrakcyjną metodą... wale wszędzie interfejsy, nie wiem po co, ale tak często jest w przykładach.

Hmm i tam chyba, funkcja apply powinna mieć jakiś argument nie? String jak dobrze patrze.
Edit: I dlaczego setMapper nie może przyjmować Function<String,T> tylko musi mieć rozszerzony interface? Czy to jest po to zeby generyk wyglądał ładnie czy faktycznie będzie zawierał jakieś wspólne metody? Bo jak nie bedzie zawierał tak owych, to nie będzie potrzebna hierarchia ---> nie będzie potrzebna factory class.

Dlatego obudowałem Function w nową klasę, bo Function przyjmuje tylko 1 wartość w apply, a tutaj ja potrzebuję podać 2: multiplyBy oraz pattern czyli o ile ma mnożyć znalezione i jakimi paternami szukać... 1 multiply do n patternów.

2

Mam wrażenie, że niedługo wyjdzie Ci http://www.fizzbuzz.enterprises z tych wszystkich wzorców.

5

Też tak czytam Twoje tematy i przypomniało mi się https://medium.com/@webseanhickey/the-evolution-of-a-software-engineer-db854689243

0

Wyrzuć to keyword Mother, bo to bardziej przypomina Matkę Mapperów, Pierwszą Tego Imienia, Niewstrzykniętą, Królową Pierwszych Encji niż kod.
To jest zwykła implementacja interfejsu to już o niebo lepiej (ale dalej brzydko) można by to nazwać MyMapperImpl...

Tak nawiasem mówiąc, to w builderze powinieneś mieć DI, więc nie tworzysz sobie fabryki, ani MATKI_MAPPERÓW, tylko sobie przekazujesz skądś, czyli:

builder.setMapper(myMapperMother) //Ojej, gdzie to 12
builder.setMapper(myMapperFactory.produceMapper(12)) 

Jeśli w builderze setujesz parametry mappera (czyli to 12), to dla pierwszego przypadku szlag wszystko trafił - i tak musisz stworzyć fabrykę:

class MyMapperFactory {

    public MyMapper<String, Integer> produceMapper(int multiplyBy) {
        return new MyMapperMother(multiplyBy);
    }
}

builder.setMapper(myMapperFactory.produceMapper(12)) 

I generalnie dla buildera sprowadziło się to do tego samego.
I teraz pytanie: Czy wielka lambda, czy osobna klasa w fabryce. Odpowiedź zależna od ilości kodu w fabryce. Jak się zrobi za dużo linii, to przydałoby się flaki wydzielić do osobnej klasy

Natomiast, jeśli nie setujesz żadnych parametrów mapperowi w builderze, to nie ma sensu tworzyć do niego fabryki, która za każdym odpaleniem buildera tworzyłaby nowy obiekt

1 użytkowników online, w tym zalogowanych: 0, gości: 1