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 class BoardGameService<br>
{<br>
public static List boardGameList = new List<br>
{<br>
new BoardGame<br>
{<br>
Id = 1, Name = "Catan", Active = true<br>
},<br>
new BoardGame<br>
{<br>
Id = 2, Name = "Gaia", Active = true<br>
},<br>
};</p>
<p> public BoardGame Get(int boardGameId)<br>
{<br>
return boardGameList.FirstOrDefault(x => x.Id == boardGameId);<br>
}</p>
<p> public void Add(BoardGame boardGame)<br>
{<br>
boardGameList.Add(boardGame);<br>
}</p>
<p> public void Delete(int boardGameId)<br>
{<br>
var boardGame = boardGameList.FirstOrDefault(x => x.Id == boardGameId);<br>
if (boardGame != null)<br>
boardGame.Active = false;<br>
}<br>
}<br>
Jak widać, wykorzystujemy tutaj obiekt modelu BoardGame
<br>
public class BoardGame<br>
{<br>
public int Id { get; set; }<br>
public string Name { get; set; }<br>
public bool Active { get; set; }<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 interface INewBoardGameService<br>
{<br>
string GetBoardGameName(int boardGameId);<br>
NewBoardGame GetNewBoardGame(int boardGameId);<br>
void AddBoardGame(NewBoardGame newBoardGame);<br>
void DeleteBoardGame(int boardGameId);<br>
}<br>
Wspomniany model NewBoardGame różni się od BoardGame jedną właściwością – IsDeleted:
<br>
public class NewBoardGame<br>
{<br>
public int Id { get; set; }<br>
public string Name { get; set; }<br>
public bool IsDeleted { get; set; }<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 string GetBoardGameName(int boardGameId)<br>
{<br>
var boardGame = Get(boardGameId);<br>
if (boardGame != null)<br>
return boardGame.Name;<br>
return 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 NewBoardGame GetNewBoardGame(int boardGameId)<br>
{<br>
var boardGame = Get(boardGameId);<br>
return new NewBoardGame<br>
{<br>
Id = boardGame.Id,<br>
Name = boardGame.Name,<br>
IsDeleted = !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 void AddBoardGame(NewBoardGame newBoardGame)<br>
{<br>
var boardGame = new BoardGame<br>
{<br>
Id = newBoardGame.Id,<br>
Name = newBoardGame.Name,<br>
Active = !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 void DeleteBoardGame(int boardGameId)<br>
{<br>
Delete(boardGameId);<br>
}<br>
Ostatecznie cała klasa adaptera będzie wyglądała następująco:
<br>
public class BoardGameServiceAdapter : BoardGameService, INewBoardGameService<br>
{<br>
public void AddBoardGame(NewBoardGame newBoardGame)<br>
{<br>
var boardGame = new BoardGame<br>
{<br>
Id = newBoardGame.Id,<br>
Name = newBoardGame.Name,<br>
Active = !newBoardGame.IsDeleted<br>
};<br>
Add(boardGame);<br>
}</p>
<p> public string GetBoardGameName(int boardGameId)<br>
{<br>
var boardGame = Get(boardGameId);<br>
if (boardGame != null)<br>
return boardGame.Name;<br>
return string.Empty;<br>
}</p>
<p> public NewBoardGame GetNewBoardGame(int boardGameId)<br>
{<br>
var boardGame = Get(boardGameId);<br>
return new NewBoardGame<br>
{<br>
Id = boardGame.Id,<br>
Name = boardGame.Name,<br>
IsDeleted = !boardGame.Active<br>
};<br>
}</p>
<p> public void DeleteBoardGame(int 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.
Pingback: Wzorzec adapter – cz. 2 adapter obiektu – programmer-girl