Entonces tengo dos clases: SoccerPlayer y IceHockeyPlayer
Ambos tienen su propia interfaz con algunos métodos: ISoccerPlayer e IIceHockeyPlayer

Jugador de fútbol:

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
    }
}    

Jugadora de hockey sobre hielo:

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
    }

}  

Luego, creé una clase que contiene un SoccerPlayer y un IceHockeyPlayer que implementa ambas interfaces, este sería mi adaptador.
Los métodos en esta clase solo llaman a los métodos correctos de SoccerPlayer o 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);
    }

}  

¿Es esta una implementación correcta de un patrón de adaptador? Si no, ¿qué necesitaría cambiar para hacerlo uno?

0
Lukas 28 feb. 2018 a las 15:42

4 respuestas

La mejor respuesta

Eso es más de una fachada.

Para un adaptador, tendrías algo como

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

Y adaptadoras como

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);
    }
}

Que "adaptaría" al jugador de hockey para "convertirse" en SportsPlayer; así que en realidad es un conjunto de métodos diferente.

Editar:

Aquí hay un uso del adaptador para el JDK real.

¿Sabes que puedes usar try-with-resources que cerrará los recursos automáticamente y puedes cerrar ExecutorService s después de enviar tus tareas? Bueno, probar con recursos exige un AutoCloseable y el ExecutorService no implementa eso. Un adaptador al rescate:

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();
    }
}

Así que ahora puedes usarlo así:

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

Y el servicio se registrará para el cierre al final del método.

4
daniu 1 mar. 2018 a las 15:18

No es estrictamente hablando un adaptador.
Utiliza más bien una composición de objetos respaldados en 2 interfaces:

public class Adapter implements ISoccerPlayer, IIceHockeyPlayer 

El patrón del adaptador GOF se adapta generalmente a un objeto (pero puede ser múltiple) a una interfaz específica para permitir que los clientes manipulen el tipo de interfaz mientras que los objetos adaptados utilizados en el adaptador pueden No proporcionar los métodos necesarios para la interfaz del cliente.

Por ejemplo, tome esta interfaz de cliente:

interface SportPlayer {
    void play();
}

Suponga que SoccerPlayer no tiene el método play() sino un método funcionalmente equivalente con otro nombre: playSoccer().
Para poder adaptar un objeto SoccerPlayer a SportPlayer, puede crear un SoccerAdapter:

public class SoccerAdapter implements SportPlayer {
   private SoccerPlayer soccerPlayer;

   public SoccerAdapter(SoccerPlayer soccerPlayer){
      this.soccerPlayer = soccerPlayer;          
   }
   public void play(){
        soccerPlayer.playSoccer();
   }
} 
0
davidxxx 28 feb. 2018 a las 12:55

El patrón del adaptador resuelve el problema cuando hay un código Consumer existente y un código Producer existente y hay una incompatibilidad entre el tipo de acceso de código Consumer y {{X3} } código producido tipo.

[Consumer y el código Producer no son los términos estándar, prefiero usarlos para que mi punto sea fácil de entender]

Para resolver este problema, creamos un código Adapter separado que consume el tipo producido del código Producer y lo transforma al tipo consumido por el código 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.

Para obtener el código, puede consultar (fácil de entender) https://www.geeksforgeeks.org/adapter-pattern /

0
nits.kk 28 feb. 2018 a las 13:47

No, ese no es el patrón del adaptador. Utiliza un adaptador para asignar el comportamiento / métodos de lo que la persona que llama espera a lo que proporciona el proveedor.

Ejemplo:

Digamos que quieres construir un bot que maneje a tus jugadores. Simplemente sabe que un reproductor se parece a esta interfaz (reutilizo su ejemplo, si eso es significativo o no está fuera del alcance de esta pregunta):

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

Un adaptador para esa interfaz podría verse así:

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);
  }
}

Como puede ver, SoccerPlayerAdapter "se adapta" SoccerPlayer a Player, es decir, asigna el método shoot(int meters) a kickFootball(int meters), etc.

Nota: normalmente utiliza adaptadores si las interfaces no se pueden implementar directamente o no tendría mucho sentido hacerlo por otras razones. En su ejemplo (y por lo tanto el mío), tendría más sentido hacer que los jugadores implementen directamente la interfaz Player y refactoricen kickFootball(meters) al método más general shoot(meters), etc.

0
Thomas 28 feb. 2018 a las 12:51