Wzorce projektowe – wzorzec Adapter

Często adapter jest wyjaśniany na podstawie gniazdka i wtyczki. Np. laptopa przystosowanego do polskich wtyczek sieciowych nie można bezpośrednio podłączyć do wtyczki sieciowej w Wielkiej Brytanii. Trzeba zastosować “przejściówkę” tudzież adapter który pozwoli na połączenie tych dwóch rzeczy.

Wzorzec adapter powstał w celu umożliwienia współpracy pomiędzy niedostosowanymi do siebie systemami. Wykorzystywany jest w szczegolności gdy chcemy aby nasza aplikacja współpracowała z zewnętrznymi bibliotekami/systemami których interfejsy nie są dostosowane do naszego systemu. Stosuje się go gdy wykorzystanie istniejącej klasy jest niemożliwe ze względu na jej niekompatybilny interfejs.

Adapter ma więc na celu takie połańczanie niekompatybilnych interesów bez modyfikacji aby cały system spójnie działał.

Najważniejszymi elementami tego wzorca są interfejs i klasa adaptera. Adapter nazywany Wrapper’em, wzorcem przejściowym należy do grupy wzorców strukturalnych. Opakowuje zaimplementowane metody interfejsu.

Implementacja tego wzorca może przybrać formę dziedziczenia

Obrazek posiada pusty atrybut alt; plik o nazwie Przechwytywanie-1.png
Dziedziczenie

lub kompozycji. Niezależnie od implementacji klient ma zawsze zależność z interfejsem.

Obrazek posiada pusty atrybut alt; plik o nazwie Przechwytywanie.png
kompozycja-zależność

W tym wzorcu występują następujące elementy:

Target – definiuje interfejs wykorzystywany przez klienta.

Client – współpracuje z obiektami oraz wykorzystuje interfejs

Adaptee – istniejący interfejs który teraz powinien zostać przystosowany do współpracy z zewnętrznym interfejsem/systemem.

Adapter – interfejs który stanowi połączanie pomiędzy klientem a niekompatybilnym interfejsem.

W początkowym systemie zaimplementowano interfejs “Shape” z kilkoma metodami oraz klasy reprezentujące prostokąt oraz koło. Interface jest Targetem.

public interface Shape {
      void draw();
      void resize();
} 

 public class Rectangle implements Shape {

      @Override
      public void draw() {
      System.out.println("Drawing Rectangle");
     }

      @Override
      public void resize() {
      System.out.println("Resizing Rectangle");
      }
} 

 public class Circle implements Shape {

      @Override
      public void draw() {
      System.out.println("Drawing Circle");
      }

      @Override
      public void resize() {
      System.out.println("Resizing Circle");
      }
} 

Teraz klasa Drawing która pełni role klienta -> Client

public class Drawing {

 List<Shape> shapes = new ArrayList<Shape>();

 public Drawing() {
    super();
}

 public void addShape(Shape shape) {
    shapes.add(shape);
}

 public List<Shape> getShapes() {
  return new ArrayList<Shape>(shapes);
}

public void draw() {
  if (shapes.isEmpty()) {
     System.out.println("Nothing to draw!");
   } else {
      shapes.stream().forEach(shape -> shape.draw());
  }
}

 public void resize() {
  if (shapes.isEmpty()) {
      System.out.println("Nothing to resize!");
  } else {
      shapes.stream().forEach(shape -> shape.resize());
  }
 }
}

Oraz klasa wywoławcza “Main” wraz w wynikiem na konsoli.

public class Main {

 public static void main(String[] args) {

    System.out.println("Creating drawing of shapes...");
    Drawing drawing = new Drawing();
    drawing.addShape(new Rectangle());
    drawing.addShape(new Circle());

    System.out.println("Drawing...");
    drawing.draw();
          
    System.out.println("Resizing...");
    drawing.resize();
}

Wynik na konsoli:

Creating drawing of shapes...
Drawing...
Drawing Rectangle
Drawing Circle

Resizing...
Resizing Rectangle
Resizing Circle 

Leave a Comment

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *