Refaktoryzacja - zastąpienie instrukcji switch polimorfizmem - potrzebna pomoc

1

Cześć, przychodzę z prośbą o nakierowanie mnie na właściwe rozwiązanie.
(Nie jestem zawodowym programistą)

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":

  1. 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 )
  2. 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.
  3. 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ę.
  4. 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ąć?

  1. Wzorzec FabrykaAbstrakcyjna jest względnie zrozumiały dla mnie i chce iść w tym kierunku - czy to dobry kierunek? potrzebuje rady kogoś doświadczonego.
  2. 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");
            }
        }

0

Jest cisza, bo jakoś nie jasno opisałem? Czy problem mam taki? ;)

0
Varran napisał(a):

Prosba o przeniesienie dyskusji do tego watku:

https://4programmers.net/Forum/Inzynieria_oprogramowania/356566-refaktoryzacja_zastapienie_instrukcji_ifswitch_polimorfizmem_potrzebna_pomoc?p=1806728#id1806728

A w zasadzie to dlaczego? Myślisz że ludzie nieznający C# i normalnie nie zaglądający do działu C# lepiej powiedzą ci jak zrefaktoryzować kod w C#?

1

Ja bym zaczął od zmiany polskiego nazewnictwa na angielskie. Źle się na to patrzy

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