Wstrzykiwanie serwisu czy statyczne metody

Wstrzykiwanie serwisu czy statyczne metody
NA
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:68
0

Ostatnio pisałem sobie program w GUI i wyświetlanie alertów wyodrębniłem do osobnej klasy. Były tam metody, które wyświetlały różne okienka powiadomień. Było też kilka innych tak jakby klas-serwisów. I w sumie wszystko zacząłem wstrzykiwać do klas, w których potrzebowałem danego serwisu. Zastanawiam się jednak czy nie wygodniej byłoby jakby klasa AlertsService (czy inne, które nie trzymają żadnego stanu) udostępniała statyczne metody do wyświetlania okienek? Skąd wiedzieć kiedy lepiej wstrzyknąć serwis, a kiedy stworzyć statyczną metodę? Są jakieś zasady / dobre praktyki co kiedy?

LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:33 minuty
  • Postów:8409
2

Pomyśl (albo poczytaj w necie, jeśli nic ci nie przychodzi do głowy) jakie zalety i wady ma wstrzykiwanie serwisów /*/ , a jakie zalety i wady ma zrobienie singletona/zmiennej globalnej ze statycznymi metodami. I pomyśl jakie inne rozwiązania widzisz.

A następnie spróbuj pomyśleć jakie mogą być konsekwencje. Co się stanie jak wybierzesz tę metodę? Spróbuj wyobrazić sobie w jaki sposób będziesz chciał rozwijać swój program za tydzień czy za miesiąc. Która metoda będzie bardziej odpowiednia? (jeśli nie wiesz, to możesz zrobić eksperyment i wybrać którąkolwiek metodę i potem już będziesz bardziej doświadczony, nawet jeśli wybierzesz złą, albo szczególnie jeśli wybierzesz złą - człowiek uczy się na błędach).`

Skąd wiedzieć kiedy lepiej wstrzyknąć serwis, a kiedy stworzyć statyczną metodę?

Za pomocą wyobraźni. Spróbuj sobie wyobrazić konsekwencje swoich wyborów.

Są jakieś zasady / dobre praktyki co kiedy?

Zasady i dobre praktyki są wymyślane przez ludzi, a nie są niczym inherentnym. Ważniejsze są konsekwencje danych wzorców, ich korzyści i ograniczenia (a to można łatwo w necie znaleźć, ponieważ popularne wzorce są dość dobrze opisane).

/*/ np. wpisujesz w google: advantages disadvantages dependency injection i czytasz. Oczywiście nie znaczy to, żeby zawsze wierzyć bezgranicznie to, co się wyczyta. Najlepiej samemu sprawdzić w praktyce.


edytowany 4x, ostatnio: LukeJL
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
3

Statyczna metoda ma ten minus że nie może być polimorficzna i generalnie jeśli sam pobierasz zależności to trudno je potem "podmienić" czy to inne implementacje czy to na jakieś stuby w trakcie testów.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
3

Jest inna droga - wrzucanie zależności przez konstruktor - czyli dependency injection. Nie potrzebujesz kontenera (Spring) i prosto możesz wszystko testować w Javie.
Jest niewiele przypadków gdzie metody statyczne się sprawdzają - jakieś konwertery, proste obliczenia itp. (gdzie wiadomo, że nawet na potrzeby testów nie ma sensu metody inaczej implementować).


jeden i pół terabajta powinno wystarczyć każdemu
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
3
Naitoreivun napisał(a):

Są jakieś zasady / dobre praktyki co kiedy?

  1. jeśli implementujesz jakieś uniwersalne funkcje w stylu sinus, cosinus - to jest duża szansa że wystarczy Ci jedna wersja w aplikacji (w ogóle w bazie kodu) - wtedy możesz użyć utility class
  2. jeśli zależność wstrzykujesz 2-5 razy w całej aplikacji to wystarczy "ręczne" wstrzyknięcie przez konstruktor
  3. jeśli aplikacja jest mała ale liczba wstrzykiwań idzie w setki (np. połączenie z bazą) to lepiej zastosować poniższe:
    3.1) jeśli implementujesz serwis który może być tylko jeden w aplikacji - singleton
    3.2) jeśli wstrzykiwany obiekt może mieć warianty, lepiej zastosować registry bo możesz wykorzystać kilka różnych wersji singletona
  4. gdy aplikacja jest już spora, to lepiej to jakoś ogarnąć odgórnie (np. przez kontener IoC, ustandaryzowany XML lub cokolwiek co ma jakąś architekturę, którą można zmieniać przekrojowo w całej aplikacji - np. dla wszystkich klas implementujących interfejs X robić krok Y przy tworzeniu obiektu)
NA
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:68
0

Bardzo dziękuję za wszystkie rady :)

Jeszcze żeby rozwiać ewentualne wątpliwości: mówiąc o ręcznym wstrzykiwaniu macie na myśli żeby w mainie potworzyć odpowiednie instancje klas i ładnie je sobie przekazywać do konstruktorów innych klas, a dopiero potem ruszyć całą aplikację?


Jeśli chodzi o Springa to bardzo polubiłem różne jego moduły, szczególnie Spring Data, więc nawet jeśli nie robię aplikacji webowej, to dla uproszczenia łączenia się z bazą, robienia zapytań, konfiguracji wszystkiego (dziękuję Pan Spring Boot) to lubię go dodać do aplikacji, więc skoro DI jest w zestawie, to też go chętnie użyję.

edytowany 1x, ostatnio: Naitoreivun
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0

Ale jak już DI Springa to posłuchaj chociaż jednego z twórców i rób to przez konstruktor.
http://olivergierke.de/2013/11/why-field-injection-is-evil/


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 1x, ostatnio: jarekr000000
NA
Tak, jak najbardziej tego używam do tej pory. Jedyny przypadek kiedy to nie działa to gdy mamy cykl, referencje w dwie strony. Trochę patologiczna sytuacja, ale się zdarza.
GregoryI
  • Rejestracja:ponad 9 lat
  • Ostatnio:6 minut
  • Postów:238
0

To jeszcze ja się podepnę pod temat z kilkoma pytaniami. Android Studio / Java.

1. Ściągnąłem sobie ostatnio przykład jakiejś aplikacji z oficjalnego gita GoogleSamples (nie pamiętam dokładnie czy to był ten, ale jeden z takich, który osoba bez doświadczenia wzięła by za wzór no bo od google itp.), i nagminnie używają tam konstrukcji:

Kopiuj
(przykładowa nazwa)
public class NetworkManager {
    private static NetworkManager mNetworkManager = null;

<EDIT -> zapomniałbym, konstruktor domyślny prywatny>

    public static NetworkManager getInstance() {
        if (mNetworkManager == null) {
            mNetworkManager = new NetworkManager();
        }
        return mNetworkManager;
    }
...reszta metod niestatyczna
}

Jak to ma się w stosunku do pól i metod statycznych? Czy taka klasa jest singletonem?
Pytam, bo wrzucano to było prawie wszędzie, do klas rodzaju model/manager, a ze względu, że jest to static, inicjowane będzie tylko raz.
W ogóle dobra/zła praktyka?

2. Odnośnie metod statycznych i klas utility.
Jakie powinno być podejście do klas posiadających tylko metody statyczne, nie przechowujących i zapisujących żadnych zmiennych jako swoje pola, działających na zasadzie: podanie parametrów wejściowych -> klasa wykonuje operacje/ konwersje/manipulacje itp -> zwrócenie nowej poprawnej wartości.
Święcona woda i egzorcyzmy, czy ma to może zastosowanie?
Pytam w kontekście tego, że mogą być przeprowadzone jakieś bardziej zaawansowane operacje, ale z trzymaniem zasady parametr wejściowy -> operacje -> zwrotny parametr wyjściowy, oraz klasa sama w sobie nie ma żadnych zmiennych.
Przykładowo, konwersja współrzędnej geograficznej z double to string ze zmianą z postaci numerycznej na czasową (czy jak tam zwał ten format):

Kopiuj
class JakaśKlasa {

double latitude = 51.321321231321321;
String str = FormatAndValueConventer.setGeoCoordinateStr(latitude, true);

System.out.println(str);
<wyświetla wartość np. 51°23'13''N*>
}


class FormatAndValueConventer {
    /** Set geographical coordinate string
     * @param coordinate geographic coordinate to forge
     * @param isLatitude define if given coordinate is latitude or longitude
     * @return formatted geographical coordinate string
     * example: 51°23'13''N*
     */
    public static String setGeoCoordinateStr(Double coordinate, boolean isLatitude) {
        String str;
        str = convertCoordinateToStr(coordinate);
        str = replaceSpecialSigns(str);

        int indexOfDoubleApostropheInStr;
        indexOfDoubleApostropheInStr = getIndexOfDoubleApostropheInStr(str);
        str = subtractStr(str, indexOfDoubleApostropheInStr);
        str = setGeoDirectionSymbol(str, coordinate, isLatitude);

        return str;
    }

    private static String convertCoordinateToStr(Double coordinate) {
        return Location.convert(coordinate, Location.FORMAT_SECONDS);
    }

    private static String replaceSpecialSigns(String str) {
        if (str.contains(":")) {
            str = str.replaceFirst(":", "°");
        }
        if (str.contains(":")) {
            str = str.replaceFirst(":", "'");
        }
        if (str.contains(",")) {
            str = str.replaceFirst(",", "''");
        }
        return str;
    }

    private static int getIndexOfDoubleApostropheInStr(String str) {
        if (str.contains("''")) {
            return str.indexOf("''");
        } else {
            return str.length() + 1;
        }
    }

    private static String subtractStr(String str, int indexOfSignInStr) {
        if (indexOfSignInStr < str.length() && str.contains("''")) {
            return str.substring(0, indexOfSignInStr+2);
        } else {
            return str;
        }
    }

    private static String setGeoDirectionSymbol(String str, Double coordinate, boolean isLatitude) {
        if (isLatitude) {
            return appendSymbolForLatitude(str, coordinate);
        } else {
            return appendSymbolForLongitude(str, coordinate);
        }
    }

    private static String appendSymbolForLatitude(String str, Double coordinate) {
        if (coordinate < 0) {
            return str + "S";
        } else {
            return str + "N";
        }
    }

    private static String appendSymbolForLongitude(String str, Double coordinate) {
        if (coordinate < 0) {
            return str + "W";
        }
        else {
            return str + "E";
        }
    }
}
edytowany 3x, ostatnio: GregoryI
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0

Ogólnie to statiki nie są takie złe jak je malują jeśli nie manipulują stanem i nie wprowadzają efektów ubocznych. Twój przykład byłby prawie dobry... ale jest tu inny antypattern.
Jeśli masz jakieś Geokordynaty to opakuj te Double czy Stringi w klasę Geocoord i tego używaj. Inaczej pałętasz się przez cały system z jakimiś Doublami i Stringami i nikt nie wie o co chodzi. W Kotlinie albo Scali jest nawet Type alias. Czyli możemy sobie powiedzieć, że Double to Geocoord i tego używać (mimo, że pod spodem jest np. całkiem zwykły Double).


jeden i pół terabajta powinno wystarczyć każdemu
GregoryI
  • Rejestracja:ponad 9 lat
  • Ostatnio:6 minut
  • Postów:238
0

@jarekr000000 Dzięki za szybką odpowiedź.

A jak z pierwszym pytaniem? Tego rodzaju klasa to singleton, czy może nie?

*A, i jak coś opakowane już jest w klasę Location z biblioteki androida, tylko tutaj wpisałem double. :)

edytowany 3x, ostatnio: GregoryI
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
1

Tak - to paskudny singleton. Niestety raczej w takim przypadku antypattern - utrudnia testowanie (no bo jeśli np. na potrzeby testów chcemy mieć NetworkManagera, który bez Networka działa... ) i ogólnie potrafi rozwalić design (bo wszędzie można wrzucić wywołanie). To jest nawet dwa poziomy niebezpieczniejsze niż Beany / Singletony Springowe.
Czasami Singleton jest OK. Ale to raczej bardzo, bardzo rzadko i w dość technicznych przypadkach np. jakiś LoggerFactory, SysConfig (tu już bywa, że słabo) czy tym podobne.


jeden i pół terabajta powinno wystarczyć każdemu
GregoryI
Coś mi właśnie tak nie bardzo to wyglądało, ale, że było to z oficjalnego źródła, to gdybym nie zapytał dałbym kredyt zaufania.
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

@jarekr000000: to jak masz globalnego configa apki jakbyś bez singletonów z tym handlował?


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
0

Mario Fusco mówi Reader Monad - ja się jakoś bez niczego specjalnego obywam. (Raczej widzę, że za często Clock wstrzykuję -> i tu chyba coś wykombinuje).

Generalnie jak coś zaczyna być wstrzykiwane wszędzie (albo w wiele miejsc) to znak, że coś poszło nie tak. Z Configiem sobie radzę, żeby takiej miazgi nie mieć.
(No ale z Clockiem nie - rozłazi mi się).


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 2x, ostatnio: jarekr000000
Shalom
to znak, że coś poszło nie tak albo znak że to logger :P
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)