C# · Programowanie · Wzorce projektowe

Wzorzec adapter – cz. 2 adapter obiektu

We wcześniejszym wpisie opisałam działanie wzorca adapter klasy. Dla przypomnienia: jest on wykorzystywany na przykład wtedy, gdy klient zdefiniuje swoje wymagania na podstawie jakiegoś interfejsu. Wystarczy, że dostarczy klasę, która implementuje ten interfejs i dziedziczy po istniejącej klasie. I tyle.

Co jednak, gdy klient nie przygotuje takiego interfejsu? Tylko dostarczy jakąś klasę spełniającą wymagania? Wtedy należy użyć wzorca adapter obiektu.

Skopiujmy przykładową klasę serwisu BoardGameService (jest ona taka sama, jak w poprzednim poście)

<br>
public&nbsp;class&nbsp;BoardGameService<br>
{<br>
	public&nbsp;static&nbsp;List&lt;BoardGame&gt;&nbsp;boardGameList&nbsp;=&nbsp;new&nbsp;List&lt;BoardGame&gt;<br>
	{<br>
		new&nbsp;BoardGame<br>
		{<br>
			Id&nbsp;=&nbsp;1,&nbsp;Name&nbsp;=&nbsp;"Catan",&nbsp;Active&nbsp;=&nbsp;true<br>
		},<br>
		new&nbsp;BoardGame<br>
		{<br>
			Id&nbsp;=&nbsp;2,&nbsp;Name&nbsp;=&nbsp;"Gaia",&nbsp;Active&nbsp;=&nbsp;true<br>
		},<br>
	};<br>
	<br>
	public&nbsp;BoardGame&nbsp;Get(int&nbsp;boardGameId)<br>
	{<br>
		return&nbsp;boardGameList.FirstOrDefault(x&nbsp;=&gt;&nbsp;x.Id&nbsp;==&nbsp;boardGameId);<br>
	}<br>
	<br>
	public&nbsp;void&nbsp;Add(BoardGame&nbsp;boardGame)<br>
	{<br>
		boardGameList.Add(boardGame);<br>
	}<br>
	<br>
	public&nbsp;void&nbsp;Delete(int&nbsp;boardGameId)<br>
	{<br>
		var&nbsp;boardGame&nbsp;=&nbsp;boardGameList.FirstOrDefault(x&nbsp;=&gt;&nbsp;x.Id&nbsp;==&nbsp;boardGameId);<br>
		if&nbsp;(boardGame&nbsp;!=&nbsp;null)<br>
		{<br>
			boardGame.Active&nbsp;=&nbsp;false;<br>
		}<br>
	}<br>
}<br>

wykorzystującą obiekt modelu BoardGame

<br>
public&nbsp;class&nbsp;BoardGame<br>
{<br>
	public&nbsp;int&nbsp;Id&nbsp;{&nbsp;get;&nbsp;set;&nbsp;}<br>
	public&nbsp;string&nbsp;Name&nbsp;{&nbsp;get;&nbsp;set;&nbsp;}<br>
	public&nbsp;bool&nbsp;Active&nbsp;{&nbsp;get;&nbsp;set;&nbsp;}<br>
}<br>

Załóżmy, że klient zdefiniował własną, zewnętrzną klasę ExternalBoardGameService, spełniającą swoje wymagania. Wygląda ona następująco:

<br>
public&nbsp;class&nbsp;ExternalBoardGameService<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;virtual&nbsp;string&nbsp;GetBoardGameName(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//some&nbsp;logic<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
	public&nbsp;virtual&nbsp;ExternalBoardGame&nbsp;GetNewBoardGame(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//some&nbsp;logic<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
	public&nbsp;virtual&nbsp;void&nbsp;AddBoardGame(ExternalBoardGame&nbsp;newBoardGame)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//some&nbsp;logic<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
	public&nbsp;virtual&nbsp;void&nbsp;DeleteBoardGame(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//some&nbsp;logic<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
}<br>

W tym momencie implementacja metod nie jest ważna, dlatego zostawiłam je puste (lub zwracam pusty obiekt). Ważne są metody. Żeby istniała możliwość nadpisania tych metod (podmienienia ich logiki), dodałam słowo kluczowe virtual.

Zerknijmy teraz, jak będzie wyglądała klasa adaptera. Po pierwsze, będzie dziedziczyć po obiekcie klienta ExternalBoardGameService. Dzięki temu będzie mogła skorzystać z wszystkich metod występujących w tej klasie.

<br>
public&nbsp;class&nbsp;BoardGameServiceAdapter&nbsp;:&nbsp;ExternalBoardGameService<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;void&nbsp;AddBoardGame(ExternalBoardGame&nbsp;newBoardGame)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base.AddBoardGame(newBoardGame);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;string&nbsp;GetBoardGameName(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;base.GetBoardGameName(boardGameId);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;ExternalBoardGame&nbsp;GetNewBoardGame(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;base.GetNewBoardGame(boardGameId);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;void&nbsp;DeleteBoardGame(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base.DeleteBoardGame(boardGameId);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
}<br>

W powyższym przykładzie wypisanie wszystkich metod klasy ExternalBoardGameService wraz z ich bazową implementacją nie jest potrzebne – służy tylko pokazaniu,  że zostaną wywołane metody z klasy bazowej.

Załóżmy, że zamiast metod bazowych, pochodzących z klasy ExternalBoardGameService  chcielibyśmy wywołać odpowiadajace im metody z klasy BoardGameService. Potrzebna jest nam do tego instacja klasy serwisu, którą możemy przekazać jako parametr w kontruktorze.

<br>
public&nbsp;class&nbsp;BoardGameServiceAdapter&nbsp;:&nbsp;ExternalBoardGameService<br>
{<br>
&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;BoardGameService&nbsp;_boardGameService;<br>
&nbsp;&nbsp;&nbsp;public&nbsp;BoardGameServiceAdapter(BoardGameService&nbsp;boardGameService)<br>
&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_boardGameService&nbsp;=&nbsp;boardGameService;<br>
&nbsp;&nbsp;&nbsp;}<br>
}<br>

Dzięki temu możemy teraz nadpisać odpowiednie metody wykorzystując na przykład metody z serwisu BoardGameService:

<br>
public&nbsp;class&nbsp;BoardGameServiceAdapter&nbsp;:&nbsp;ExternalBoardGameService<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;BoardGameService&nbsp;_boardGameService;<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;BoardGameServiceAdapter(BoardGameService&nbsp;boardGameService)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_boardGameService&nbsp;=&nbsp;boardGameService;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;void&nbsp;AddBoardGame(ExternalBoardGame&nbsp;newBoardGame)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;boardGame&nbsp;=&nbsp;new&nbsp;BoardGame<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Id&nbsp;=&nbsp;newBoardGame.Id,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name&nbsp;=&nbsp;newBoardGame.Name,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Active&nbsp;=&nbsp;!newBoardGame.IsDeleted<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_boardGameService.Add(boardGame);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;ExternalBoardGame&nbsp;GetNewBoardGame(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;boardGame&nbsp;=&nbsp;_boardGameService.Get(boardGameId);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(boardGame&nbsp;!=&nbsp;null)<br>
		{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;ExternalBoardGame<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Id&nbsp;=&nbsp;boardGame.Id,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name&nbsp;=&nbsp;boardGame.Name,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IsDeleted&nbsp;=&nbsp;!boardGame.Active<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>
		}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;null;<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;override&nbsp;void&nbsp;DeleteBoardGame(int&nbsp;boardGameId)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_boardGameService.Delete(boardGameId);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
}<br>

To, co warto zauważyć, to to, że nigdzie nie nadpisujemy metody GetBoardGameName(). W powyższym rozwiązaniu możemy sobie na to pozwolić – zostanie zawsze wywołana logika zdefiniowana przez serwis zewnętrzny ExternalBoardGame.

PS – przykładowy kod można pobrać pod linkiem.


Podoba Ci się to, co tworzę? Chcesz dostawać informacje o:
– wydarzeniach, które organizuję lub wspieram (np. konferencje, meetupy, webinary)
– inicjatywach, które organizuję lub wspieram (np. GeekWeekWro, DevAdventCalendar)
– moich prelekcjach, kursach i szkoleniach
– wyróżnionych artykułach z mojego bloga

0% SPAMu, 100% informacji! Krótko i na temat.

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie na Google

Komentujesz korzystając z konta Google. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s