Wpis z mikrobloga

#cpp

Stworzyłem swój pierwszy "troszeczkę bardziej" rozbudowany programik obiektowy służący do walidacji danych nowego klienta banku. Generalnie nie chodzi o samą walidację, bo kilku mechanizmów brakuje, np. jak się poda hasło ze spacją, to akceptuje. Chodzi mi raczej o nakierowanie, czy sama struktura programu obiektowego jest poprawna. Co zmienić, dobre praktyki itp... jakiś wzorzec może byłoby lepiej tu zastosować, a może nie...

https://github.com/VanQator/bankAccount
  • 23
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

@VanQator: największy problem jaki widzę to mocne połączenie pomiędzy operacjami IO a twoimi klasami. To dość częsty błąd wśród początkujących. Jak chcesz mieć to ładnie to klasy odpowiedzialne za trzymanie poprawnej wartości, czyli wszystkie ValidCośTam powinny rzucać wyjątek, albo używać jakiegoś innego mechanizmu raportowania błędów. Tam gdzie jest logika nie powinno być IO, bo czegoś takiego nie da się testować i reużywać.
Inne sprawy:
- w cpp jest raczej konwencja,
  • Odpowiedz
@VanQator:

for (int i = 0; i < name.length(); i++)
{
if (name.length() == 0)

Ten kawałek kodu to oksymoron. Gdy name.length() == 0 to nigdy nie wejdziemy do pętli
  • Odpowiedz
@VanQator:
pirmo - dla nowego moze to byc upierdliwe i zbyteczne, ale nie mieszac logiki z wyswietlaniem to kiedys zaprocentuje i sam sobie bedziesz chcial obciagnac za tak genialne rozwiazanie
drugie - uzywaj wiecej std, w wiekszosci przypadkow bo to jest piekne, zgrabne i wiekszosci przypadkow jak juz pisalem wydajne np. twoja walidaje tutaj https://github.com/VanQator/bankAccount/blob/master/validBalance.cpp#L10 mozna zastapic pieknym 1 linijkowcem:

bool isValid = find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
po trzecie
  • Odpowiedz
via Wykop Mobilny (Android)
  • 2
@VanQator: dobre aplikacje są budowane tak, aby sama główna logika (biznesowa) aplikacja była oddzielona zarówno od użytkownika, jak i warstwy "persistent" ( powinny być osobno od ).

Takie podejście umożliwia rozszerzalność aplikacji w postaci np. dodania GUI bez znacznych zmian w głównej logice.
  • Odpowiedz
@longstar: Czyli zamiast wyświetlania lepiej np. stworzyć jakieś zmienne w obiekcie, które są flagmi poszczególnych błędów, i tak walidowac poprze ustawianie ich?
  • Odpowiedz
via Wykop Mobilny (Android)
  • 1
@VanQator: to nie muszą być flagi.
Może to być np. klasa reprezentująca problemy w walidacji - w sensie może to być typ złożony, który przenosi jeszcze dodatkowe informacje, albo nawet prosty Enum jak ci się podoba.
  • Odpowiedz
@patrolez: potem pomyślę, jak to rozwiązać, chcę też dodać jakiś mechanizm agregujący klientów w jednej strukturze, i nwm czy najlepiej zastosować tutaj zwykły vector, czy jakiś wzorzec typu kompozyt
  • Odpowiedz
@VanQator:

możesz zrobić to na 2 sposoby:

1, tradycyjnie w C++, rzucasz w środku konstruktora wyjątek i łapiesz go:
ValidBalance
  • Odpowiedz
@VanQator: nie powiedziałbym, że to programowanie obiektowe. W każdym paradygmacie powinna być seperacja, w proceduralnym wymieszane IO nie boli tak bardzo (ale też boli) jak w obiektowym. W funkcyjnym paradygmacie mieszanie IO i logiki jest upierdliwe, więc tam nawet nie trzeba się pilnować, bo słuszna droga jest najczytelniesza
  • Odpowiedz
@VanQator: taka uwaga generalna po samym tylko otworzeniu repozytorium - nie bój się nowych plików i unikaj konstrukcji typu "mainHeader.h".

Osobny plik nagłówkowy i .cpp dla każdej z klas jest zdecydowanie lepszym rozwiązaniem.

A poza tym to co pisali poprzednicy - oddziel IO od logiki.

Ja zawsze byłem bojownikiem pisania '{' linijkę niżej, ale o ile to Twój mały projekt, to tylko i wyłącznie kwestia Twoich preferencji - tym niemniej
  • Odpowiedz
@Saly: Ok powiedzmy, że funkcja validPassword obiektu ValidPassword zeraca wyjątek, bo użytkownik podał złe hasło. Wyjątek jest obsługiwany w konstruktorze obiektu ValidPassword. Problem jest jednak taki, że nawet po zwróceniu błędu o nieptaridłowym haśle, obiekt ValidPassword zostanie zainicjalizowy... czy się mylę
  • Odpowiedz
@VanQator: wyjątek przelatuje przez konstruktor. Miejsce, gdzie łapiesz, to tam gdzie tworzysz obiekt. Jak widać na moim przykładzie jak poleci wyjątek to obiekt nie powstanie, nie wykona się return tylko wskoczysz do catch
  • Odpowiedz
@Saly: Ok, ale powstanie obiekt Account, który będzie posiadał pole balance_ zainicjalizowane śmieciową wartością. Ten wyjątek oczywiście łapię w konstruktorze klasy ValidBalance?
  • Odpowiedz
@Saly: Ok, no to załóżmy, że chcę zrezygnować całkowicie z IO. To co mnie interesuje to utworzenie obiektu Account tylko i wylącznie w wypadku, gdy podczas tworzenia żadnego z obiektu typu ValidBalance, ValidPassword... nie zostanie wyrzucony wyjątek.
  • Odpowiedz