Cześć, przychodzę z prośbą o nakierowanie mnie na właściwe rozwiązanie.
(Nie jestem zawodowym programistą)
(PS2. Pisałem na forum C# i .NET ale tam nie bylo odzewu wiec ponawiam tutaj.)
Opis funkcjonalności programu który już jest i działa.
Program jest wykorzystywany w magazynie podczas pakowania wyrobów w pudełka jednostkowe. Praca polega na włożeniu wyrobu do pudelka, sczytaniu z wyrobu numeru seryjnego czytnikiem kodów kreskowych, program na podstawie odczytu czytnikiem drukuje etykietę z tym numerem i etykietę tą pracownik magazynu nakleja na zamknięte pudełko. To tak bardzo w skrócie. Dodatkowo zrobiłem to tak ze program jest obsługiwany tylko czytnikiem kodów kreskowych, praktycznie nie wymaga podchodzenia do klawiatury ani myszki. Czyli po uruchomieniu programu kursor jest na jednym TextBox'ie i zależnie jaki typ odczytu zostanie mu wczytany program zachowa się inaczej.
Typu "rozkazów":
- odczyt nr zlecenia - program pobiera z bazy danych artykuł tego zlecenia i otwiera okno dla kierownika gdzie weryfikowane są dane czy wszystko jest ok, jeżeli ok to kierownik zatwierdza i magazynier może używać programu do pakowania tego zlecenia (kierownik używa klawiatury w swoim oknie )
- odczyt nr seryjnego - program pobiera nr seryjny i drukowana jest etykieta na Zebrze z nr seryjnym, nazwa wyrobu i grafikami wcześniej pobranymi dla tego artykułu z odczytu nr zlecenia. Dodatkowo co odczyt jest pobierany czas wydruku i na podstawie tego rejestrowany jest czas pakowania każdego z wyrobów i łącznie całego zlecenia.
- odczyt "Raport" - program drukuje etykietę na której jest mały raport dla magazyniera do rozliczenia swojej pracy, co pakował, kiedy, ile zapakował i w jakim czasie łącznie z średnim czasem pakowania na sztukę.
- odczyt "Czyść" - czyści stan programu i przywraca do ustawień początkowych gdzie należy znów odczytać nr zlecenia żeby ustawić program do pakowania nowych wyrobów.
Obecnie dekoder typów odczytów/rozkazów jest na "if'ach" a sama logika interpretacji odczytu na jednym dużym switchu który w swoich case'ach ma kolejne switche - przykład na samym dole.
Chciałbym z odczytu/rozkazu zrobić obiekt który będzie implementował jakiś interfejs z np. metodą Wykonaj(). Wtedy łatwiej będę mógł dodawać nowe typy etykiet i nowe typy rozkazów i teraz pytanie:
Jak to ogarnąć?
- Wzorzec FabrykaAbstrakcyjna jest względnie zrozumiały dla mnie i chce iść w tym kierunku - czy to dobry kierunek? potrzebuje rady kogoś doświadczonego.
- Jak maja wyglądać te obiekty "Odczyt/Rozkaz" to chyba nie będą jakieś proste encje, wyobrażam sobie ze dla odczytów typu "Raport" będę musiał wstrzyknąć mój obiekt który odpowiada za rejestracje czasów i generowanie statystyk pakowania, dla rozkazu "Czyść" powinienem wstrzyknąć obiekt "PresenteraOknaGlownego" za pomocą którego wyczyszczę stan całej aplikacji i zresetuje widok aplikacji, za pomocą odczytu "nrZlecenia" będę musiał powstrzykiwac chyba repozytoria z danymi z baz danych a w obiekcie odczytu "nrSeryjny" chyba musze wstrzyknąć obiekt odpowiedzialny za wydruki etykiet (on już będzie musiał zapanować nad tym co to za etykieta i z jaka treścią - wiec tu chyba tez wzorzec fabryka abstrakcyjna?)
Program napisałem na bazie swojego starego programu sprzed prawie 10lat jeszcze z innej firmy w WinForms pod zdarzeniami. Teraz przerabiam go na architekturę MVP, względnie dobrze idzie - stopniowo. Spod zdarzeń przenoszę kod do wydzielonych obiektów, widok już całkowicie odciąłem od logiki. Teraz mam problem z tym kawalkiem architektury logiki - jakos obawiam sie ze te obiekty "odczyty" to będą kobyły czy to dobrze?
dekoder odczytow czytnika obecnie
public class DekoderOdczytowCzytnika
{
string regexUID = @"100\d{7}\b";
string regexNrZlecenia = @"501[0-9]{7}\b";
public TypRozkazuEnum RozpoznajOdczytCzytnika(string odczyt)
{
TypRozkazuEnum wynik = TypRozkazuEnum.NiezdefiniowanyTekst;
if (odczyt == "Raport")
wynik = TypRozkazuEnum.Raport;
else if (odczyt == "Czysc")
wynik = TypRozkazuEnum.Czysc;
else if (odczyt == "WalidatorProg")
wynik = TypRozkazuEnum.WalidatorProg;
else if (Regex.IsMatch(odczyt, regexUID))
wynik = TypRozkazuEnum.OdczytUID;
else if (Regex.IsMatch(odczyt, regexNrZlecenia))
wynik = TypRozkazuEnum.OdczytNrZlecenia;
else
wynik = TypRozkazuEnum.NiezdefiniowanyTekst;
return wynik;
}
}
i fragment obiektu odpowiedzialnego za interpretacje odczytow i wydruki - tez obecnie
public class KontrolerDrukowania
{
private string nazwaDrukarki;
private DekoderOdczytowCzytnika dekoderOdczytow;
private RejestratorCzasu rejestratorCzasu;
private PresenterOknaGlownego presenterOknaGlownego;
public KontrolerDrukowania(PresenterOknaGlownego presenter)
{
this.presenterOknaGlownego = presenter;
dekoderOdczytow = new DekoderOdczytowCzytnika();
rejestratorCzasu = new RejestratorCzasu();
}
//(...........)
public void DrukujEtykiete(TypEtykiety parametryWybranejEtykiety,
string txtB_NazwaKlienta,
string txtB_UID,
string txtB_WersjaProg)
{
if (txtB_NazwaKlienta != null
&& txtB_UID != null
&& txtB_NazwaKlienta != "Nazwa_Klienta"
&& txtB_UID != "UID"
&& txtB_WersjaProg != "Wersja_Programu")
{
IEtykietaDrukowalna etykietaDoWydruku = null;
switch (dekoderOdczytow.RozpoznajOdczytCzytnika(txtB_UID))
{
case TypRozkazuEnum.Raport:
switch (parametryWybranejEtykiety.RozmiarPapieruEtykiety)
{
case RozmiarPapieruEtykietyEnum.Rozmiar82x56:
etykietaDoWydruku = new EtykietaRaport_82x56(
txtB_NazwaKlienta,
rejestratorCzasu.ZwrocTekstem_CalkowityCzasPakowania(),
rejestratorCzasu.ZwrocTekstem_SredniCzasPakowania());
break;
case RozmiarPapieruEtykietyEnum.Rozmiar40x20:
Informator.PokazBlad(
"Nie można obecnie drukowac raportu na małej etykiecie",
"Za mała etykietka na raport");
break;
default:
Informator.PokazBlad(
"Niezdefiniowany rozmiar papieru etkiety",
"Blad wyboru etykiety");
break;
}
presenterOknaGlownego.WyczyscPoleCzytnikaUID();
break;
case TypRozkazuEnum.Czysc:
rejestratorCzasu.WyczyscRejestrOdczytow();
presenterOknaGlownego.ZresetujWidok();
Informator.PokazInformacje("Wyczyszczenie danych historii wydrukow i czasow pakowania", "Zerowanie aplikacji");
break;
case TypRozkazuEnum.OdczytUID:
switch (parametryWybranejEtykiety.RozmiarPapieruEtykiety)
{
case RozmiarPapieruEtykietyEnum.Rozmiar82x56:
etykietaDoWydruku = new EtykietaWydruk_82x56(
txtB_UID,
txtB_NazwaKlienta,
txtB_WersjaProg);
break;
case RozmiarPapieruEtykietyEnum.Rozmiar40x20:
etykietaDoWydruku = new EtykietaWydruk_40x20(
txtB_UID);
break;
default:
Informator.PokazBlad(
"Niezdefiniowany rozmiar papieru etkiety",
"Blad wyboru etykiety");
break;
}
rejestratorCzasu.DodajOdczyt(new CzasOdczytuUID(txtB_UID, DateTime.Now));
presenterOknaGlownego.WyczyscPoleCzytnikaUID();
presenterOknaGlownego.WyswietlPodsumowanie(rejestratorCzasu.ZwrocIloscZarejestrowanychOdczytow().ToString() + " [szt.]");
break;
default:
//TODO tutaj zamiast wydruku dodac wyswietlenie messageBox
etykietaDoWydruku = new EtykietaBledu();
presenterOknaGlownego.WyczyscPoleCzytnikaUID();
break;
}
if (etykietaDoWydruku != null)
{
//zewnetrzna biblioteka do drukarek Zebra
RawPrinterHelper.SendStringToPrinter(
NazwaPrzypisanejDrukarkiZebra,
etykietaDoWydruku.ZwrocKodEtykietyZPL());
}
}
else
{
Informator.PokazBlad("Któreś z poniższych pól zostało niewłaściwie wypełnione:" + Environment.NewLine +
"- 'Nazwa Klienta'" + Environment.NewLine +
"- 'Wersja Programu'" + Environment.NewLine +
"- 'pole ID' ?", "Źle wypełnione pola");
}
}
wymuszał obsługę wszystkich przypadków
- exhaustivescibi_92