【问题标题】:Is this a correct implementation of an adapter pattern?这是适配器模式的正确实现吗?
【发布时间】:2018-02-28 12:42:27
【问题描述】:

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

}  

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

【问题讨论】:

    标签: java design-patterns adapter


    【解决方案1】:

    这更像是一个门面。

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

    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?好吧,try-with-resources 需要 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();
        }
    }
    

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

    【讨论】:

      【解决方案2】:

      不,那不是适配器模式。您使用适配器将调用者期望的行为/方法映射到提供者提供的内容。

      例子:

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

      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) 等会更有意义。

      【讨论】:

        【解决方案3】:

        严格来说,它不是适配器。
        您使用支持 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();
           }
        } 
        

        【讨论】:

        • 根本不是适配器。
        • @lexicore 写解释需要时间。可能做了错误的选择。
        【解决方案4】:

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

        [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/

        【讨论】:

          猜你喜欢
          • 2011-09-08
          • 1970-01-01
          • 2017-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多