Wzorzec adapter – cz. 1 adapter klasy

Cel

W książkach można przeczytać, że głównym celem tego wzorca jest zaadaptowanie (przystosowanie) istniejącej klasy do formy, którą oczekuje klient. Klientem w tym przypadku jest dowolny obiekt, który wywołuje nasz kod i wymaga odpowiedniego interfejsu.

Teoria może być łatwa, ale trzeba jeszcze umieć zastosować ją w praktyce. Stwórzmy więc przykładową klasę BoardGameService.

<br>
public&nbsp;class&nbsp;BoardGameService<br>
{<br>
	public&nbsp;static&nbsp;List&nbsp;boardGameList&nbsp;=&nbsp;new&nbsp;List<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>
	};</p>
<p>	public&nbsp;BoardGame&nbsp;Get(int&nbsp;boardGameId)<br>
	{<br>
		return&nbsp;boardGameList.FirstOrDefault(x&nbsp;=&gt;&nbsp;x.Id&nbsp;==&nbsp;boardGameId);<br>
	}</p>
<p>	public&nbsp;void&nbsp;Add(BoardGame&nbsp;boardGame)<br>
	{<br>
		boardGameList.Add(boardGame);<br>
	}</p>
<p>	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>
			boardGame.Active&nbsp;=&nbsp;false;<br>
	}<br>
}<br>

Jak widać, wykorzystujemy tutaj 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>

Adapter klasy

Jeśli klient definiuje swoje wymagania na podstawie jakiegoś interfejsu, sprawa jest całkiem prosta. Wystarczy dostarczyć klasę, która:

  • implementuje ten interfejs,
  • dziedziczy po istniejącej klasie

W naszym przykładzie załóżmy, że klient chciałby, żeby interfejs INewBoardGameService wyglądał następująco:

<br>
public&nbsp;interface&nbsp;INewBoardGameService<br>
{<br>
	string&nbsp;GetBoardGameName(int&nbsp;boardGameId);<br>
	NewBoardGame&nbsp;GetNewBoardGame(int&nbsp;boardGameId);<br>
	void&nbsp;AddBoardGame(NewBoardGame&nbsp;newBoardGame);<br>
	void&nbsp;DeleteBoardGame(int&nbsp;boardGameId);<br>
}<br>

Wspomniany model NewBoardGame różni się od BoardGame jedną właściwością – IsDeleted:

<br>
public&nbsp;class&nbsp;NewBoardGame<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;IsDeleted&nbsp;{&nbsp;get;&nbsp;set;&nbsp;}<br>
}<br>

Przeanalizujmy po kolei przez wszystkie metody:

  • Metoda GetBoardGameName

Nie mamy odpowiednika tej metody w naszej klasie. Ale możemy stworzyć logikę, która pobiera obiekt BoardGame i zwraca tylko parametr Name:

<br>
public&nbsp;string&nbsp;GetBoardGameName(int&nbsp;boardGameId)<br>
{<br>
	var&nbsp;boardGame&nbsp;=&nbsp;Get(boardGameId);<br>
	if&nbsp;(boardGame&nbsp;!=&nbsp;null)<br>
		return&nbsp;boardGame.Name;<br>
	return&nbsp;string.Empty;<br>
}<br>

  • Metoda GetNewBoardGame

Mamy odpowiednik tej metody w naszej klasie. Jedyny problem to to, że jest zwracany obiekt BoardGame, a nie NewBoardGame. Co możemy z tym zrobić? Możemy napisać odpowiednią logikę w metodzie adaptera:

<br>
public&nbsp;NewBoardGame&nbsp;GetNewBoardGame(int&nbsp;boardGameId)<br>
{<br>
	var&nbsp;boardGame&nbsp;=&nbsp;Get(boardGameId);<br>
	return&nbsp;new&nbsp;NewBoardGame<br>
	{<br>
		Id&nbsp;=&nbsp;boardGame.Id,<br>
		Name&nbsp;=&nbsp;boardGame.Name,<br>
		IsDeleted&nbsp;=&nbsp;!boardGame.Active<br>
	};<br>
}<br>

  • Metoda AddNewBoardGame

Tutaj jest podobnie – mamy odpowiednik metody w naszej klasie, aczkolwiek znowu nie zgadzają się obiekty modeli. Trzeba napisać odpowiednią logikę:

<br>
public&nbsp;void&nbsp;AddBoardGame(NewBoardGame&nbsp;newBoardGame)<br>
{<br>
	var&nbsp;boardGame&nbsp;=&nbsp;new&nbsp;BoardGame<br>
	{<br>
		Id&nbsp;=&nbsp;newBoardGame.Id,<br>
		Name&nbsp;=&nbsp;newBoardGame.Name,<br>
		Active&nbsp;=&nbsp;!newBoardGame.IsDeleted<br>
	};<br>
	Add(boardGame);<br>
}<br>

  • Metoda DeleteBoardGame

W tym przypadku metody pokrywają się. Nie trzeba pisać logiki obsługującej. Metoda adaptera będzie wyglądała następująco:

<br>
public&nbsp;void&nbsp;DeleteBoardGame(int&nbsp;boardGameId)<br>
{<br>
	Delete(boardGameId);<br>
}<br>

Ostatecznie cała klasa adaptera będzie wyglądała następująco:

<br>
public&nbsp;class&nbsp;BoardGameServiceAdapter&nbsp;:&nbsp;BoardGameService,&nbsp;INewBoardGameService<br>
{<br>
	public&nbsp;void&nbsp;AddBoardGame(NewBoardGame&nbsp;newBoardGame)<br>
	{<br>
		var&nbsp;boardGame&nbsp;=&nbsp;new&nbsp;BoardGame<br>
		{<br>
			Id&nbsp;=&nbsp;newBoardGame.Id,<br>
			Name&nbsp;=&nbsp;newBoardGame.Name,<br>
			Active&nbsp;=&nbsp;!newBoardGame.IsDeleted<br>
		};<br>
		Add(boardGame);<br>
	}</p>
<p>	public&nbsp;string&nbsp;GetBoardGameName(int&nbsp;boardGameId)<br>
	{<br>
		var&nbsp;boardGame&nbsp;=&nbsp;Get(boardGameId);<br>
		if&nbsp;(boardGame&nbsp;!=&nbsp;null)<br>
			return&nbsp;boardGame.Name;<br>
		return&nbsp;string.Empty;<br>
	}</p>
<p>	public&nbsp;NewBoardGame&nbsp;GetNewBoardGame(int&nbsp;boardGameId)<br>
	{<br>
		var&nbsp;boardGame&nbsp;=&nbsp;Get(boardGameId);<br>
		return&nbsp;new&nbsp;NewBoardGame<br>
		{<br>
			Id&nbsp;=&nbsp;boardGame.Id,<br>
			Name&nbsp;=&nbsp;boardGame.Name,<br>
			IsDeleted&nbsp;=&nbsp;!boardGame.Active<br>
		};<br>
	}</p>
<p>	public&nbsp;void&nbsp;DeleteBoardGame(int&nbsp;boardGameId)<br>
	{<br>
		Delete(boardGameId);<br>
	}<br>
}<br>

Tyle na dzisiaj. W kolejnym wpisie opiszę drugi rodzaj tego wzorca, czyli adapter obiektu.

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.

Jedna uwaga do wpisu “Wzorzec adapter – cz. 1 adapter klasy

  1. Pingback: Wzorzec adapter – cz. 2 adapter obiektu – programmer-girl

Dodaj komentarz