Итак, у меня есть два класса: SoccerPlayer и IceHockeyPlayer
Они оба имеют собственный интерфейс с некоторыми методами: ISoccerPlayer и IIceHockeyPlayer

Футболист:

public class SoccerPlayer implements ISoccerPlayer {

    public String[] teammembers;

    @Override
    public void kickFootball(int meters) {
        // Kick the football
    }

    @Override
    public void runForward(double speed) {
        // Run forward
    }

    @Override
    public void addTeammembers(String[] memberNames) {
        // Add the members
    }
}    

Хоккеист

public class IceHockeyPlayer implements IIceHockeyPlayer {

    public ArrayList<String> teammembers;

    @Override
    public void hitPuck(int meters) {
        // Hit the puck
    }

    @Override
    public void skateForward(double speed) {
        // Skate forward
    }

    @Override
    public void addTeammembers(ArrayList<String> memberNames) {
        // Add the members
    }

}  

Затем я создал класс, который содержит и SoccerPlayer, и IceHockeyPlayer, который реализует оба интерфейса. Это будет мой адаптер.
Методы в этом классе просто вызывают правильные методы SoccerPlayer или IceHockeyPlayer:

public class Adapter implements ISoccerPlayer, IIceHockeyPlayer {

    public SoccerPlayer soccerplayer;
    public IceHockeyPlayer icehockeyplayer;

    public Adapter(SoccerPlayer soccerplayer, IceHockeyPlayer icehockeyplayer) {
        this.soccerplayer = soccerplayer;
        this.icehockeyplayer = icehockeyplayer;
    }

    // SoccerPlayer
    @Override
    public void kickFootball(int meters) {
        this.soccerplayer.kickFootball(meters);
    }

    @Override
    public void runForward(double speed) {
        this.soccerplayer.runForward(speed);
    }

    @Override
    public void addTeammembers(String[] memberNames) {
        this.soccerplayer.addTeammembers(memberNames);
    }

    // IceHockeyPlayer
    @Override
    public void hitPuck(int meters) {
        this.icehockeyplayer.hitPuck(meters);
    }

    @Override
    public void skateForward(double speed) {
        this.icehockeyplayer.skateForward(speed);
    }

    @Override
    public void addTeammembers(ArrayList<String> memberNames) {
        this.icehockeyplayer.addTeammembers(memberNames);
    }

}  

Это правильная реализация шаблона адаптера? Если нет, что мне нужно изменить, чтобы сделать его одним?

0
Lukas 28 Фев 2018 в 15:42

4 ответа

Лучший ответ

Это больше фасад.

Для адаптера у вас будет что-то вроде

interface SportsPlayer {
    public void play(int meters);
    public void move(double speed);
}

И адаптеры, как

class IceHockeyPlayerAdapter implements SportsPlayer {
    private IceHockeyPlayer player;
    public IceHockeyPlayerAdapter(IceHockeyPlayer p) { player = p; }

    public void play(int meters) {
        player.playPuck(meters);
    }
    public void move(double speed) {
        player.skateForward(speed);
    }
}

Который "приспособил бы" хоккеиста к тому, чтобы "стать" SportsPlayer; так что на самом деле это другой набор методов.

РЕДАКТИРОВАТЬ:

Вот использование адаптера для реального JDK.

Вы знаете, что вы можете использовать try-with-resources, который автоматически закрывает ресурсы, и вы можете завершить работу ExecutorService после отправки ваших задач? Ну, попытка с ресурсами требует AutoCloseable, а ExecutorService этого не реализует. Адаптер для спасения:

public class AutocloseableExecutorService implements ExecutorService, AutoCloseable {
    private ExecutorService delegate;
    public AutocloseableExecutorService(ExecutorService d) {
        delegate = d;
    }
    // delegate ExecutorService methods to implement the interface
    public void execute(Runnable r) { delegate.execute(r); 
    // ...

    // implement close() for AutoCloseable
    public void close() {
        delegate.shutdown();
    }
}

Так что теперь вы можете использовать это так:

public void submitTasks(Runnable... rs) {
    try (AutocloseableExecutorService executor = new AutocloseableExecutorService(
             Executors.newSingleThreadExecutor())) {
        for (Runnable r : rs) executor.submit();
    }
}

И служба будет зарегистрирована для отключения в конце метода.

4
daniu 1 Мар 2018 в 15:18

Строго говоря, это не адаптер.
Вы используете скорее композицию объектов с поддержкой двух интерфейсов:

public class Adapter implements ISoccerPlayer, IIceHockeyPlayer 

Шаблон адаптера GOF обычно адаптирует один объект (но может быть несколько) к одному конкретному интерфейсу , чтобы позволить клиентам манипулировать типом интерфейса, в то время как адаптированные объекты, используемые в адаптере, могут не предоставлять методы, необходимые для интерфейса клиента.

Например, возьмем этот клиентский интерфейс:

interface SportPlayer {
    void play();
}

Предположим, что SoccerPlayer не имеет метода play(), но имеет функционально эквивалентный метод с другим именем: playSoccer().
Чтобы иметь возможность адаптировать SoccerPlayer объект к SportPlayer, вы можете создать SoccerAdapter:

public class SoccerAdapter implements SportPlayer {
   private SoccerPlayer soccerPlayer;

   public SoccerAdapter(SoccerPlayer soccerPlayer){
      this.soccerPlayer = soccerPlayer;          
   }
   public void play(){
        soccerPlayer.playSoccer();
   }
} 
0
davidxxx 28 Фев 2018 в 12:55

Шаблон адаптера решает проблему, когда существует существующий код Consumer и существующий код Producer, и существует несовместимость между типом принятия кода Consumer и {{X3} } код, произведенный тип.

[Consumer и Producer код не являются стандартными терминами, я предпочитаю использовать их для упрощения понимания моей точки зрения]

Чтобы решить эту проблему, мы создаем отдельный код Adapter, который использует полученный тип из кода Producer и преобразует его в тип, используемый кодом Consumer.

 Consumer ---consume (TypeX) //accepts TypeX, Existing code
 Producer   ----produce () : TypeY //returns TypeY, Existing code
 Adapter     ---- adapt(TypeY) : TypeX //New code to work with two existing code.accepts TypeY adapts it to TypeX and returns the same.

Код можно использовать (легко понять) https://www.geeksforgeeks.org/adapter-pattern /

0
nits.kk 28 Фев 2018 в 13:47

Нет, это не шаблон адаптера. Вы используете адаптер для отображения поведения / методов того, что ожидает вызывающий абонент, к тому, что предоставляет поставщик.

Примере:

Допустим, вы хотите создать бота, который бы обслуживал ваших игроков. Он просто знает, что плеер выглядит как этот интерфейс (я снова использую ваш пример, вне зависимости от того, является ли он значимым или нет):

interface Player {
  void shoot(int meters);
  void move(double speed);
  addTeammembers(ArrayList<String> memberNames);
}

Адаптер для этого интерфейса может выглядеть так:

class SoccerPlayerAdapter implements Player {
  SoccerPlayer soccerplayer; //set via constructor

  void shoot(int meters) {
    soccerplayer.kickFootball(meters);
  }

  void move(double speed){
    soccerplayer.runForward(speed);
  }

  addTeammembers(ArrayList<String> memberNames) {
    soccerplayer.addTeammembers(memberNames);
  }
}

Как вы можете видеть, SoccerPlayerAdapter "адаптируется" SoccerPlayer к Player, то есть он отображает метод shoot(int meters) на kickFootball(int meters) и т. Д.

Примечание: вы обычно используете адаптеры, если интерфейсы не могут быть реализованы напрямую, или нет смысла делать это по другим причинам. В вашем примере (и, следовательно, моем) было бы более разумно просто заставить игроков напрямую реализовать интерфейс Player и рефакторинг kickFootball(meters) для более общего метода shoot(meters) и т. Д.

0
Thomas 28 Фев 2018 в 12:51