W części pierwszej opisałem ogólne zasady jakimi staram się posługiwać przy refaktoryzacji. Z redukowałem kod odpowiedzialny za wybór aktywnego (ostatniego) narzędzia.

W tej części postanowiłem, że skupie się na ostatecznym wyborze narzędzia i jego zastosowaniu na płótnie.

Poniżej kod oryginalny

Część kodu czyli wybór narzędzia została poddana zmianą w poprzedniej części. 

Każda z instrukcji warunkowych odpowiedzialna jest za przygotowanie i wykonanie operacji na płótnie. Wykonanie tych metod odbywa się na zdarzeniu mouse_up na płótnie.

Postanowiłem stworzyć bardziej uniwersalną konstrukcje, która umożliwi w prostrzy sposób rozszerzenie funkcjonalności oraz wywołanie tych metod.

Poniżej kod:

Opis

Do wykonania tego zadania użyłem klas abstrakcyjnych oraz interfejsów.  Postanowiłem budować narzędzie od samego dołu, składać je z części. Na każde narzędzie składa się płótno na którym narzędzie ma „operować”.

Klasa AGraphicCanvas  definiuje płótno w tym wypadku mam w konstruktorze obiekt klasy PictureBox. Druga klasa która dziedziczy po klasie AGraphicCanvas jest klasa ACoordinates, która definiuje współrzędne na płótnie oraz rozmiar narzędzia. Rozmiar mógłby być wrzucony w osobną klasę ale na tym etapie zbyt mało elementów składało by się na tę klasę.

W klasie ACoordinates mamy pokaźnych rozmiarów kontruktor to dlatego, że w właściwościach tejże klasy umieszczone są właściwości typu Point które wymagają współrzędnych x i y. Są one odpowiedzialne za umieszczenie punktów na płótnie. Dodatkowo w w konstruktorze wołam interfejs ICoordinates, który ma za zadanie przypisanie wartości do właściwości typu Point.

Kod klasy definiującej interfejs:

Interfejs ICoordiantes jest stosunkowo prosty, dzięki jego zastosowaniu wyrzuciłem pewną część logiki po za klasę abtrakcyjną i odwróciłem zależność.

Dwie podstawowe klasy tworzące narzędzie zostały pokazane poniżej.

Kolejnym krokiem jest wybór typu narzędzia. Mam do wyboru dwa Brush oraz Pen. W tym momencie uznałem, że rozdzielę klasy definiujące typ na dwie klasy abstarkcyjne.  Pierwsza ABrushToolType definiuje podstawę do narzędzi wykorzystujących Brush, druga to APenToolType, która definiuje  podstawę do narzędzi wykorzystujących Pen.

Klasy są bardzo podobne:

Wyjaśnienie.

Klasy nie są skomplikowane bardzo do siebie podobne różni je tylko jedna metoda, a właściwie jej parametr interjefs do klasy, która zwraca typ Brush lub Pen. Mam tu także parametr kolor, który również mógłby być osobną klasą, ponieważ może zawierać różne style kolorowania. Na tym etapie jednak jest on prostym wyborem kolorów (jednolitych) i nie ma sensu budować dodatkowej klasy dla niego. Tutaj również można by dodać klasę odpowiedzialną za styl tyczy się szczególnie klas wykorzystujących klasę Brush.

Możliwe ścieżki

Rozbicie klasy z typem narzędzia. Klasa mogla zostać jedna, zamiast metody abstrakcyjnej można było użyć metody virtualnej z parametrami, które były by interfejsami. W ten sposób uzyskał bym możliwość nadpisania tych klas w klasach dziedziczących bez wymuszania ich definicji .  Uznałem jednak, że jedna klasa może zawierać za dużą odpowiedzialność, gdyż w przyszłości można by rozbudować aplikacje o kolejne narzędzia które potrzebowały by innych składowych do poprawnego działania, a jedna taka klasa stała by się za duża. Na tej podstawie uznałem, że warto to rozdzielić,  w przyszłości dodanie kolejnego typu narzędzia będzie polegało na dodaniu nowej klasy abstrakcyjnej dziedziczącej po ACoordinates równoległej do reszty typów już zdefiniowanych (będzie to dodatkowa gałąź).

W części trzeciej definicja poszczególnych narzędzi oraz ich wywołanie w kodzie aplikacji

 

 

 

 

 

Kategorie: Archiwum