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.
public class BoardGameService { public static List boardGameList = new List { new BoardGame { Id = 1, Name = "Catan", Active = true }, new BoardGame { Id = 2, Name = "Gaia", Active = true }, }; public BoardGame Get(int boardGameId) { return boardGameList.FirstOrDefault(x => x.Id == boardGameId); } public void Add(BoardGame boardGame) { boardGameList.Add(boardGame); } public void Delete(int boardGameId) { var boardGame = boardGameList.FirstOrDefault(x => x.Id == boardGameId); if (boardGame != null) boardGame.Active = false; } }
Jak widać, wykorzystujemy tutaj obiekt modelu BoardGame
public class BoardGame { public int Id { get; set; } public string Name { get; set; } public bool Active { get; set; } }
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:
public interface INewBoardGameService { string GetBoardGameName(int boardGameId); NewBoardGame GetNewBoardGame(int boardGameId); void AddBoardGame(NewBoardGame newBoardGame); void DeleteBoardGame(int boardGameId); }
Wspomniany model NewBoardGame różni się od BoardGame jedną właściwością – IsDeleted:
public class NewBoardGame { public int Id { get; set; } public string Name { get; set; } public bool IsDeleted { get; set; } }
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:
public string GetBoardGameName(int boardGameId) { var boardGame = Get(boardGameId); if (boardGame != null) return boardGame.Name; return string.Empty; }
- 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:
public NewBoardGame GetNewBoardGame(int boardGameId) { var boardGame = Get(boardGameId); return new NewBoardGame { Id = boardGame.Id, Name = boardGame.Name, IsDeleted = !boardGame.Active }; }
- Metoda AddNewBoardGame
Tutaj jest podobnie – mamy odpowiednik metody w naszej klasie, aczkolwiek znowu nie zgadzają się obiekty modeli. Trzeba napisać odpowiednią logikę:
public void AddBoardGame(NewBoardGame newBoardGame) { var boardGame = new BoardGame { Id = newBoardGame.Id, Name = newBoardGame.Name, Active = !newBoardGame.IsDeleted }; Add(boardGame); }
- 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:
public void DeleteBoardGame(int boardGameId) { Delete(boardGameId); }
Ostatecznie cała klasa adaptera będzie wyglądała następująco:
public class BoardGameServiceAdapter : BoardGameService, INewBoardGameService { public void AddBoardGame(NewBoardGame newBoardGame) { var boardGame = new BoardGame { Id = newBoardGame.Id, Name = newBoardGame.Name, Active = !newBoardGame.IsDeleted }; Add(boardGame); } public string GetBoardGameName(int boardGameId) { var boardGame = Get(boardGameId); if (boardGame != null) return boardGame.Name; return string.Empty; } public NewBoardGame GetNewBoardGame(int boardGameId) { var boardGame = Get(boardGameId); return new NewBoardGame { Id = boardGame.Id, Name = boardGame.Name, IsDeleted = !boardGame.Active }; } public void DeleteBoardGame(int boardGameId) { Delete(boardGameId); } }
Tyle na dzisiaj. W kolejnym wpisie opiszę drugi rodzaj tego wzorca, czyli adapter obiektu.
PS – przykładowy kod można pobrać pod linkiem.
Jedna myśl na temat “Wzorzec adapter – cz. 1 adapter klasy”