Walidacje wprowadzanych danych - da się ładniej?

0

Czesc,
Probuje napisac walidacje wprowadzanych danych ale wszystko co znajduje w sieci dziala zle. Generalnie stworzyłem taki kod :

int result;
	while (!(cin >> result) || result < 1 || result > 5) {
		cout << "Bledne dane." << endl;
		while (getchar() != '\n');
		cin.clear();
		cin.sync();
	}

I faktycznie to działa, pobierany jest znak aż nie bedzie to liczba z przedziału 1-5. Jednak prosiłbym was o opinię, czy można to napisać jakoś lepiej?

1

W jakim celu użyta jest metoda synchronizująca cin.sync();? Wg mnie jest zbędna.

1

Poza tym co napisał @YooSy, ładniej można wyrzucając wszystko do funkcji, na przykład tak:

int get_int(int a, int b) {
    int res;
    while (!(cin >> res) || res < a || res > b) {
        cout << "Bledne dane." << endl;
        while (getchar() != '\n');
        cin.clear();
    }
    return res;
}
...
int result = get_int(1, 5);
0
#include <iostream>
#include <string>
#include <limits>
#include <type_traits>

template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
get_arithmetic(T min_bound, T max_bound,
        const std::string& prompt_msg = "Wprowadź liczbę: ",
        const std::string& error_msg = "Błędne dane.") {
    T value;
    std::cout << prompt_msg;
    while (!(std::cin >> value) || (value < min_bound) || (value > max_bound)) {
        std::cerr << error_msg << '\n';
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cin.clear();
        std::cout << prompt_msg;
    }
    return value;
}

int main() {
    int a = get_arithmetic(2, 5);
    std::cout << "Wprowadziłeś a = " << a << '\n';
    float b = get_arithmetic(2.3, 5.4, "Wprowadź liczbę z zakresu [2.3, 5.4]: ");
    std::cout << "Wprowadziłeś b = " << b << '\n';
    double c = get_arithmetic(2.5, 8.1,
            "Wprowadź liczbę z zakresu [2.5, 8.1]: ",
            "Czy Ty baranie czytasz komunikaty?");
}

Nie wiem czy "ładniej". Z pewnością elastyczniej.

1

@Mokrowski: spagetti code. Funkcja robi wszystko - pobiera dane, waliduje, wypisuje komunikat. Złamane SRP. I nazywa się fatalnie ("pobierz arytmetycznie"?).

@autor: podziel to na funkcje/metody, każda z nich zajmuje się tylko jedną rzeczą: jedna tylko pobiera dane od użytkownika (z cin), kolejna tylko waliduje, kolejna tylko wyświetla komunikat o błędzie, ostatnia spina to w całość i zwraca wynik. Nigdy nie pisz metod robiących wiele rzeczy, jeśli coś jest spoza domeny metody - wyrzuć to do innej metody i wywołaj ją, a jeśli coś jest z zupełnie innej bajki albo klasa zbyt spuchła - wyrzuć to do innej klasy, a referencję do klasy wstrzyknij przez IoC.

0
ŁF napisał(a):

@Mokrowski: spagetti code. Funkcja robi wszystko - pobiera dane, waliduje, wypisuje komunikat. Złamane SRP. I nazywa się fatalnie ("pobierz arytmetycznie"?).

@autor: podziel to na funkcje/metody, każda z nich zajmuje się tylko jedną rzeczą: jedna tylko pobiera dane od użytkownika (z cin), kolejna tylko waliduje, kolejna tylko wyświetla komunikat o błędzie, ostatnia spina to w całość i zwraca wynik. Nigdy nie pisz metod robiących wiele rzeczy, jeśli coś jest spoza domeny metody - wyrzuć to do innej metody i wywołaj ją, a jeśli coś jest z zupełnie innej bajki albo klasa zbyt spuchła - wyrzuć to do innej klasy, a referencję do klasy wstrzyknij przez IoC.

Kod @Mokrowski'ego to nie jest ładny kod (głównie chyba dlatego, że to przerost formy nad treścią, może nawet i podpada pod spaghetti), ale nie jest prawdą, że łamie SRP. Po pierwsze, nie jesteśmy w programowaniu obiektowym. Po drugie, dzielenie tego na mniejsze funkcje (a już w ogóle robienie z tego klasy) to dopiero byłby przerost formy. Po trzecie, ten kod ma tylko jedną odpowiedzialność: "pobierz dane wymuszając poprawność". W końcu po czwarte, SRP to nie świętość. :)

1

nie jest prawdą, że łamie SRP. Po pierwsze, nie jesteśmy w programowaniu obiektowym.

Co to ma do rzeczy?

Po drugie, dzielenie tego na mniejsze funkcje (a już w ogóle robienie z tego klasy) to dopiero byłby przerost formy.

Ile linijek musi mieć kod, żeby zacząć pisać go poprawnie?

Po trzecie, ten kod ma tylko jedną odpowiedzialność: "pobierz dane wymuszając poprawność".

To są dwie rzeczy. Dodaj "i wypisując komunikaty", to już będą trzy rzeczy.

W końcu po czwarte, SRP to nie świętość. :)

SOLID również nie jest świętością, olać DRY, a wzorce projektowe to mity ;-)

1

@ŁF: Nie zgadzam się. Jasno określa do czego służy i nie jest długa. Każda metodyka i zespół wykładni ma swój cel i nie jest nim fanatyzm. W przeciwnym razie należy normalizować bazy danych do 3NF "bo teoria tak każe" i nie dodawać prostych komunikatów logowania do klasy "bo to aspekt lub polityka przecież". Każdy praktyk potwierdzi że wydzielanie funkcjonalności ma sens jeśli jest podyktowane regułami biznesowymi lub innymi siłami (raczej z góry a nie z poziomu technikaliów). Orderu za S.O.L.I.D. czy GRASP (jako takich) nie dostanę w projekcie co oczywiście nie znaczy że nie należy o nich wiedzieć i nie zatrzymać się jeśli "biegnę na rozbicie nosa". Oobydwa akronimy korzenie mają właśnie w warstwie technicznej. Nie na wszystkie osie zmian także się uodpornię. Przypomnę że kod nie załatwia problemu wyboru potencjalnego rodzaju strumienia, konieczności kończenia '\n' lub nie komunikatów, zmienionego znaku zatwierdzania danych, potencjalnej specjalizacji przedziałów zamkniętych czy otwartych... (pewnie jakieś inne jeszcze bym wymyślił).
Samych linijek kodu produkcyjnego jest 9. Naprawdę chcesz za to chłostać w jedno-plikowym "programie-wprawce"?
Intencję pokazania ignore oraz szablonu dla danych arytmetycznych osiągnąłem. Nazwy zmiennych także mają sens. Sedno działania czyli "wprowadź dane od użytkownika poprawnie z konsoli z podanego zakresu" także realizuje.
A że nieładna? Cóż kwestia gustu a o nich nie dyskutuję :)
Oczywiście możesz mieć własne zdanie a ja oczywiście mam prawo się z nim nie zgodzić :)

PS Do zestawu "świętych doktrynalnych reguł" (S.O.L.I.D., DRY, GRASP, YAGNI, GoF Patterns, EAI Patterns....) dodam jeszcze Domain-driven design. Tylko ciekawe że ten ostatni ma podejście zbliżone do tego co zaproponowałem czyli "nie wydzielaj jeśli to się nie broni w domenie bo kupisz złożoność".

1
ŁF napisał(a):

nie jest prawdą, że łamie SRP. Po pierwsze, nie jesteśmy w programowaniu obiektowym.

Co to ma do rzeczy?

Masz rację, w sumie nic, SRP ma zastosowanie też wszędzie indziej. Ale... :)

Po drugie, dzielenie tego na mniejsze funkcje (a już w ogóle robienie z tego klasy) to dopiero byłby przerost formy.

Ile linijek musi mieć kod, żeby zacząć pisać go poprawnie?

Zarówno mój jak i @Mokrowski'ego kod jest poprawny (a w sumie OPa też), więc o co chodzi? A Twojego ne widzieliśmy, więc nie mogę się wypowiedzieć... Te kody mogą być niezgodne z czyimiś wytycznymi, brzydkie, nieczytelne, nieczyste itp., ale braku poprawności chyba nie da się tutaj wykazać...?

Po trzecie, ten kod ma tylko jedną odpowiedzialność: "pobierz dane wymuszając poprawność".

To są dwie rzeczy. Dodaj "i wypisując komunikaty", to już będą trzy rzeczy.

Ale o ziarnistości (granularity) słyszałeś? To jest -- wbrew może temu, co sądzisz -- rzecz dość subiektywna i zależna od konkretnego projektu, modułu/klasy, zarządzania itp... Zresztą, oryginalne sformułowanie SRP definiowało odpowiedzialność jako "reason to change" (Bob Martin), a to już naprawdę zależy od konkretnego otoczenia klasy/funkcji (czyli od całego projektu).

Rzuć okiem na przykład tutaj:
https://en.wikipedia.org/wiki/Talk:Single_responsibility_principle
https://stackoverflow.com/questions/3720516/how-granular-do-i-get-with-my-class-design-when-trying-to-follow-the-solid-princ
https://softwareengineering.stackexchange.com/questions/154723/how-to-determine-if-a-class-meets-the-single-responsibility-principle

No i warto pomyśleć chwilę, jak mają zdefiniowane odpowiedzialności standardowe klasy bibliteczne -- wydaje mi się, że raczej szerzej, niż Ty to zaprezentowałeś.

W końcu po czwarte, SRP to nie świętość. :)

SOLID również nie jest świętością, olać DRY, a wzorce projektowe to mity ;-)

Ja pisałem tylko o SRP, reszta to Twoje zdanie. :)

A poważniej -- w SOLID wszystko oprócz S (czyli właśnie SRP) jest dużo konkretniej sformułowane...

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