这是适配器模式的正确实现吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了这是适配器模式的正确实现吗?相关的知识,希望对你有一定的参考价值。

所以我有两个类: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);
    }

}  

这是适配器模式的正确实现吗?如果不是,我需要改变什么来使其成为一个?

答案

这更像是一个门面。

对于适配器,你会有类似的东西

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自动关闭资源,并且可以在提交任务后关闭ExecutorServices吗?那么,尝试资源需要一个AutoCloseableExecutorService没有实现这一点。救援的适配器:

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

并且该方法将在该方法结束时注册该服务。

另一答案

不,这不是适配器模式。您使用适配器来映射调用者对提供者提供的内容的行为/方法。

例:

假设您想构建一个处理您的玩家的机器人。它只知道一个玩家看起来像这个界面(我重用你的例子,无论这个有意义还是没有超出这个问题的范围):

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“适应”SoccerPlayerPlayer,即它将方法shoot(int meters)映射到kickFootball(int meters)等。

注意:如果接口无法直接实现,通常使用适配器,或者出于其他原因这样做没有多大意义。在你的例子中(以及我的),让玩家直接实现Player界面并将kickFootball(meters)重构为更通用的方法shoot(meters)等更有意义。

另一答案

严格来说,它不是适配器。 您使用支持2个接口的对象组合:

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();
   }
} 
另一答案

当存在Consumer代码和现有的Producer代码并且Consumer代码接受类型和Producer代码生成类型之间存在不兼容时,适配器模式解决了该问题。

[ConsumerProducer代码不是标准术语,我更喜欢使用它们来使我的观点易于理解]

为了解决这个问题,我们创建了一个单独的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/

以上是关于这是适配器模式的正确实现吗?的主要内容,如果未能解决你的问题,请参考以下文章

未调用自定义适配器 getView() 方法

片段中ListView的android自定义适配器

这是从片段中获取字符串资源的正确方法吗?

将 JSON 字符串从片段传递到适配器的问题

如何从片段返回主要活动

你可以在graphql服务器模式文件中使用片段吗