Interface class

0

Witam, mam takie pytanie. Co byście doradzili waszym zdaniem, przy tworzeniu rozbudowanych klas użytkowych. Obecnie mój sposób sprawdza się. Lecz wiem, że moje podejście jest złe. Chciał bym zmienić swoje nawyki, ale podczas zmiany chciał bym już korzystać z rad bardziej doświadczonych.

Powiedzmy, że robię klasę dość mocno rozbudowaną. Ogólnie funkcji dostępnych z zewnątrz do podpięcia jest ponad 30 funkcji. O prywatnych już nie wspomnę.

Głównie to robiłem tak iż miałem główną klasę opartą o singletona która miała w sobie pare funkcji dostępnych inicujących oraz pod klasy.
I odwoływanie się wygladało na takiej zasadzie.

NazwaKlasy.Instance.Podklasa.FunkcjaMetoda();

Segregacja taka strasznie mi się podobała bo szybko można było się odwołać do funkcji.

Poczytałem sobie o interfacach o których już dawno miałem poczytać i wprowadzić w życie ;) Macie jakieś inne pomysły albo rad ? Dla kogoś z złymi nawykami.

4
komur.l napisał(a):

Witam, mam takie pytanie. Co byście doradzili waszym zdaniem, przy tworzeniu rozbudowanych klas użytkowych (...)
Powiedzmy, że robię klasę dość mocno rozbudowaną. Ogólnie funkcji dostępnych z zewnątrz do podpięcia jest ponad 30 funkcji. O prywatnych już nie wspomnę.

Klasy nie powinny być rozbudowane ! Jeżeli za dużo mamy odpowiedzialności w klasie to jest to sytuacja zła. Wówczas pojawia się chęć by te klasy były określane mianem Magerów itp. Wówczas w nazwie klas często się pojawia takie słowo. Takie klasy są również określane mianem "boskich", oznacza to, że robią wszystko. Tutaj jakieś wczytanie plików, tutaj przetworzenie danych, a tutaj coś tam jeszcze. W konsekwencji każda klasa ma po kilkaset linii kodu, w ramach modyfikacji aplikacji wsadzamy kolejne funkcjonalności do takich klas i powstaje nam niezły bałagan -> więcej mniejszych klas zamiast jednej lub kilku super managerów, zawierających wszystko.

0

Niestety z takich mengrow chyba musze kozystac. 1 aplikacja przetwarza mega ilosc danych. Poczynajad od danych personalnych konczywszy na wlasnych konfiguracja. Ustawienia samej aplikacji jest 10 glownych sciezek wykonywania pewnej glownej raczej czynnosci. Wszystko zalezy od ustawien, wlaczonego trybu czy informacji od api. A komunikacja z api zapus logow oraz operacje dynamiczbe na plikach ('dosc duze galezie, ustawiane wedlug profilu czy tez daty').

Ogolnie mam tego w p... 3 glowne klasy dos mocno rozbudowane zarzadzajace settineg 4 klasy access sluzace do pobierania oraz zapisu czy wysylania danych.

Teraz mi dojda 2 klasy jedna mala bo ma byc szybki dostep. 2 tez rozbudowac bede musial bo ma zarzadzac jedbym automatycznym procesem potem mi dojdzie jeszcze pare .

Dla tego zeby nie miec za duzo rozbijam je i zamieszczam jedna w 2. a glowna mam do odwolan zeby juz potem szybciej pisac i nie zastanawiac sie jak ta klasa sie nazywala

2

Nie, nie musisz. Możesz mieć małe klasy realizujące dobrze pojedyncze zadania, zgodnie z zasadą SRP. I nie ma znaczenia, ile danych przetwarza aplikacja, ani nawet co w ogóle robi.
Bałagan w kodzie jest zawsze wyborem autora.

1

Umieszczając wszystko w jednym pliku czy jednej klasie tworzysz kod-spaghetti. Używając singletonów (przez wielu uważanych za antywzorzec) cofasz programowanie obiektowe do proceduralnego. Na co Ci interfejsy, skoro ilość klas możesz policzyć na palcach jednej ręki.
Zapoznaj się z zasadami SOLID, KISS, DRY, a przede wszystkim zastanów się, jak bardzo nieczytelny będzie dla Ciebie ten kod, kiedy wrócisz do niego po roku przerwy.

0

Nie chodziło mi o to, i chyba trochę źle mnie zrozumieliście.

Przykładowo robię klasę SeDriver - klasa jest odpowiedzialna za zarządzanie Driverem Selenium. W głównej klasie znajduje się instancja przeglądarki funkcja Run oraz Close returnRunBrowser - zwracajaca nazwe wybranego driver FF,Chrome,Opera.

I teraz tworze pod klasy, jedna należy do zarządzania WindowsHederami i nawigacją pomiędzy zakładkami okna
Następna zwracajaca elementy czy listy elementów za pomocą róznych metod czy nawet tworzenia złożonych Xpach oraz zawierająca metodę setAtrribute zapomocą skryptu JavaScrip.

Chodzi o to, że mam ponad 100 funkcji niezbędnie mi potrzebnych podczas pisania już działającego programu z których muszę korzystać. Np zwrócenie wszystkich windocznych fraz od użytkownika. czy propbranie Dec który selenium w prosty sposób nie ułatwia

 /// <summary>
        /// Zwraca Decs obecnie aktywnego okna
        /// </summary>
        /// <returns></returns>
        public string DecsGet()
        { 
            return GetElementByName("description").GetAttribute("content");
            
        }
 

GetElementByName - funkcja stworzona przeze mnie.

/// <summary>
        /// Zwraca wyszukany element po name
        /// </summary>
        /// <param name="serchValue"></param>
        /// <returns></returns>
        public IWebElement GetElementByName(string serchValue)
        {
            return Driver.FindElement(By.Name(serchValue));
        }
 
/// <summary>
        /// Funkcja zwracająca widoczne frazy dla uzytkownika w aktywnym oknie 
        /// </summary>
        /// <returns>return string</returns>
        public string BodyFrazGet()
        {   
            return GetElementByTagName("body").Text; // Zwracamy fraze strony
        }
 

I chodzi mi teraz o to. Że mam klasę SeDriver i chciał bym to jakoś fajnie porozbijać odwoływania się do metod. Żeby szybko móc odwoływać się do funkcji i nie mieć tego że jak wybiorę klase to nagle wyświetli mi się ponad 200 funkcji i szukaj i pamiętaj.

Więc robię tak że mam sobie klasę główną - z jakimś tam przeznaczeniem głownym i w niej podpinam pod klasy które mają inne działanie np

SeDriver.Instance.Run("chrome") // opala chroma 

SeDriver.Instance.Element.GetElementByClassName("value") //

I klasa Element jest podpięta pod główna klasę operacji do Selenium lecz jej zadaniem jest zwracanie elementów.

SeDriver.Instance.WebHeaders.GetWindowHandles() 

Dzięki takiemu rozwiązaniu. Mam klase z główna odpowiedzialnością i porozbijaną na mniejsze. Dzięki czemu już potem szybciej pisze mi się kod. Oraz szybciej odnajduje mi się moje funkcje

 /// <summary>
        /// Funkcja sprawdzajaca wszystkie owarte okna taby 
        /// </summary>
        /// <returns>zwara liste z nazwami okien</returns>
        public List<String> GetWindowHandles()
        {
            string nowWindow = GetCurrentWindowsHandles(); // Przypisanie obecnego okna 
                   
            List<String> ListWindowHandles = new List<String>(); // Tworzenie listy
            
            foreach (String window in Driver.WindowHandles)
            {
                Driver.SwitchTo().Window(window);
                ListWindowHandles.Add(window);
                
            }

            SwitchToWindow(nowWindow);

            return ListWindowHandles;

        }

I bardzo nie lubię robić całkowicie osobnych klas np Element i WebHeders powiedzmy w osobnych. I pamiętać jaka klasa jest do czego. Tak sobie podczepiam mniejsze pod główną i z rozbudową nie ma problemu.

A niestety mam dużo klas zarządzających z racji tego iż mamy dużo procesów które trzeba obsłużyć. A dodatkowo czyności wykonywane na jakimś procesie mają dużo elementów.

Np dostaje takie coś w liście bo tak jest przystosowane api. I muszę obsłużyć tego stringa

key04#GetValue#tagName$inst%21#act$inplement

key04 - klucz priorytetu
GetValue - co mam zrobic
Tagname - po czym mam szukac
inst%21 - wartości jakiej
act - rodzaj akcji które mamy rozbite też na parę gróp
inplement - dokładne odwołanie do akcji.

I naprawdę wygląda to różnie czasem brakuje czegoś i też trzeba to obsłużyć jako wartość domyślna.

I teraz jak mam sobie myśleć szukanie tego wszystkiego po 100 małych klasach i rozbudowę to dziękuje bardzo.

Dla tego stąd moje pytanie czy moje podejście zrobienie głwonej klasy przeznaczonej strikte dla jednej czynności. Obsługą danej funkcjonalności. I podpinaniem do tego pod klas które wykonują dodatkowe czyności i podklasa jest przeznaczona do jednej czyności Np sprawdzenie jakie kroki z tego kodu mają być wykonane, albo zwracające z tego kodu informacje.

Jest dobrym rozwiązaniem, a jak nie to czy macie lepsze coś.

0
 public void SetAtrributeByJQ(string serchValue, string type , string setAtrybut, string setValue )
        {
            /*  Tworzenie skryptu o postaci */
            /* jQuery('#KOTWICA a').attr('target', '_self'); */
            string jQuery = "jQuery('#" + serchValue + " " + type + "').attr('"+setAtrybut+"', '"+setValue+"');";

            IJavaScriptExecutor js = (IJavaScriptExecutor)Driver; // Wykonanie Akcji przycisku
            js.ExecuteScript(jQuery);
        }
/// <summary>
        /// Zwraca wyszukany element po Xpach  według wartosc
        /// </summary>
        /// <param name="BY">id/tagname zastepuje rodzaj elementu szukania</param>
        /// <param name="value">wartosc elementu</param>
        /// <param name="addType">bool czy ma dodac xpafa</param>
        /// <param name="type">typ szukania w przypadku bool true </param>
        /// <returns></returns>
        public IWebElement GetElementByXpach(string BY, string value, bool addType = false, string type = "")
        {
            
            string myXPatch = "//*[@"+BY+ "='" + value + "']";  // Tworzymy podstawowego Xp pafa na tybie By oraz wartosci wyszukiwanej

            if (addType == true)                               // W przypadku zagnierzdzenia 
            {
                myXPatch = myXPatch + "//" + type;             // Dodajemy do xpafcha tym zagnierzdzenia
            }

            return Driver.FindElement(By.XPath(myXPatch));    // Zwracamy znaleziony element
        }

Te co wyżej funkcje wymieniłem może nie są jakoś aż tak wymagające, ale przykładowo takich jak te 2 mam pełno. I co najważniejsze, kod może się w 1 procesie powtarzać parę razy

Pierw, trzeba sprawdzić czy element istnieje np jak nie to przejść do innego wyszukania. Zwrócić informacje jak czegoś na stronie z formularzem nie ma. Potem jak znajdzie wykonać jakies tam akcje. I poinformować czy akcje się wykonały. Następnie trzeba przeanalizować czy dane się poprawnie wpisały itp. Bardzo dużo Xpach używamy zracjii tego że do elementów do których się odwołujemy. Uchwyty wyszukania odwołują się do Diva, a my chcemy złapać to co jest w divie.

Więc niestety, ostatnio jak zacząłem pisać wszystkie funkcje to naliczyłem ich 201. A linii kodu z komentarzami jest koło 1500. Więc muszę robić klasy coś w stylu klas boskich. Jednak to jest mój pomysł i wiem, że jest nie adekwatny.

Np nigdy nie robię jednej klasy. Co się loguje pobiera dane przetwarza dane itp. I wszystko jest zawarte w jednej klasie. I nawet wprowadza dane. Bo to jest bur... totalny.

Chodziło mi po prostu o to, że czasem zrobie sobie to tak iż elementy wykorzystywane tylko do przetwarzania w klasie muszę zrobić na publicka bo odwołuję się z innej klasy bocznej ;) Bo źle ją sobie zaplanowałem.

I teraz pisząc program, czasem wyświetlają mi się funkcje ^^ które tak naprawdę nigdy z nich nie skorzystam ^^ ;) I z tym właśnie mam problem. I że ostatnio robi mi się tak coraz więcej niestety ;(

0
komur.l napisał(a):

I teraz pisząc program, czasem wyświetlają mi się funkcje ^^ które tak naprawdę nigdy z nich nie skorzystam ^^ ;) I z tym właśnie mam problem. I że ostatnio robi mi się tak coraz więcej niestety ;(

Dlatego właśnie istotne jest dzielenie kod na małe klasy o pojedynczej odpowiedzialności. Gdybyś miał utworzone takie klasy pomocniczych - np. realizujących pojedyncze kroki całego procesu, a potem napisanie klasy, która korzystając z tych klas pomocniczych wykona cały proces.
No i oczywiście, upublicznia się tylko te rzeczy, które mają być publiczne, a nie wszystkie metody.

0

Walisz koszmarne błędy ortograficzne i interpunkcyjne, mieszasz polski i angielski, nie stosujesz wszędzie camel case, a nazwy zmiennych bardzo słabo oddają to, do czego służą:
SetAtrributeByJQ(string serchValue, string type , string setAtrybut, string setValue) ->
SetAtrributeByJq(string valueToSearch, string type, string attributeName, string valueToSet)
przy czym to serchValue to id elementu do znalezienia, więc parametr dlaczego nazywa się "wartość szókana"?

GetElementByXpach(string BY, string value, bool addType = false, string type = "") ->
GetElementByXPath(string by, string value, bool addType = false, string type = "") (ale to "by" budzi moje bardzo duże wątpliwości).

"funkcje które tak naprawdę nigdy z nich nie skorzystam" - ?

[edit]
if (addType == true) - WTF? Lepiej będzie if ((addType == true) == true) :D

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