2017-04-26 38 views
1

我正在嘗試編寫接受功能接口的通用方法。看例子。任何幫助讚賞。通用功能接口使用消費者的簡單示例

更新:有編譯和運行。對意見或建議有興趣改進或澄清。

我不會創建一個類型化的抽象基類。向repeat方法中添加一個附加參數,指定執行命令的機器人似乎與其他類似示例更加一致。

想法?

import java.util.function.Consumer; 

/** 
* The intent is to create a generic function repeat() in the Robot base class 
* that will repeat actions for all subclasses of robots 
*/ 
public class GenericFunctionalInterface 
{ 
    public static void main(String[] args) 
    { 
     // Consumer<Robot> actionTurn = Robot::turnLeft; 
     // Consumer<EnhancedRobot> anyAction = EnhancedRobot::anyAction; 

     Robot r = new Robot(); 
     r.repeat(3, a->a.turnLeft()); 

     EnhancedRobot e = new EnhancedRobot(); 
     e.repeat(3, a->a.anyAction()); // cannot find symbol - method anyAction() 
     // if ((EnhancedRobot)a).anyAction() is used this works 
    } 
} 

class Robot 
{ 
    public void move() { System.out.println("MOVE"); } 

    public void turnLeft() { System.out.println("TURNLEFT"); } 

    public <T extends Robot> void repeat(int n, Consumer<T> cmd) 
    { 
     for(int i=0; i<n; i++) cmd.accept((T) this); // UPDATED: casting this to T removed -> incompatible types: Robot cannot be converted to T 
     // this will be whatever type repeat is called on 
    } 

    // added this override - specifying what robot to send the command to 
    public <T extends Robot> void repeat(int n, Consumer<T> cmd, T robot) 
    { 
     for(int i=0; i<n; i++) cmd.accept(robot); 
    } 

} 

class EnhancedRobot extends Robot 
{ 
    public void turnRight() { System.out.println("TURNRIGHT"); } 

    public void move() { System.out.println("MOVEOVERIDE"); } 

    public void anyAction() { System.out.println("ANYACTION"); } 
}  

回答

1

對於e.repeat()問題:假設你有這樣的代碼:

class SuperRobot extends Robot {} 

EnhancedRobot e = new EnhancedRobot(); 
e.repeat(3, new Consumer<SuperRobot>() { 
    @Override 
    public void accept(SuperRobot t) { 
    // ... 
    } 
}); 

然後重複方法內您要撥打:

Consumer<T> cmd; 
cmd.accept(this); 

這將失敗,因爲thisEnhancedRobot類型,但cmd預計會得到SuperRobot。這就是爲什麼你不能在那裏稱呼它。

a.anyAction()問題在那裏,因爲a的類型Robot它沒有anyAction()方法。根據聲明(T extends Robot),關於其類型的唯一安全假設是Robot或擴展它的東西。所以你不能從EnhancedRobot上調用一個方法。

+0

確定。如果我理解正確,這應該工作: public void repeat(int n,Consumer cmd,T robot) {int i = 0; i a.anyAction(),e); – Americano

+0

是的,自從您聲明'消費者'和'機器人'具有相同類型後,它就可以工作。您可以使該方法爲靜態,因爲它可以與另一個「Robot」實例一起使用。 –

1

您需要進行參數RobotConsumer的IT會接受的類型,在Enum的方式,並添加返回適當類型的this(這需要Robot是抽象的,因爲任何默認的實現將有一個方法錯誤地返回null)。

abstract class Robot<THIS extends Robot<THIS>> { 
    ... 
    public void repeat(int n, Consumer<THIS> cmd) { 
     for (int i=0; i<n; i++) { 
      cmd.accept(getThis()); 
     } 
    }  
    protected abstract THIS getThis(); 
} 

class EnhancedRobot extends Robot<EnhancedRobot> { 
    @Override protected abstract EnhancedRobot getThis() { 
     return this; 
    } 
    ... 
} 

稍微更普遍的,我想你可以聲明repeat

public void repeat(int n, Consumer<? super THIS> cmd) { 
0

在你更新的代碼,該repeat方法不使用你所調用的方法Robot實例。所以該方法可能是static

// added this override - specifying what robot to send the command to 
public static <T extends Robot> void repeat(int n, Consumer<T> cmd, T robot) 
{ 
    for(int i=0; i<n; i++) cmd.accept(robot); 
} 

要調用像

EnhancedRobot e = new EnhancedRobot(); 
Robot.repeat(3, a->a.anyAction(), e); 

但即使是robot參數不是必需的repeat方法。你可以把它聲明爲

public static void repeat(int n, Runnable cmd) 
{ 
    for(int i=0; i<n; i++) cmd.run(); 
} 

要調用像

EnhancedRobot e = new EnhancedRobot(); 
Robot.repeat(3,() -> e.anyAction()); 

足見其設計的實際問題。重複動作是否與Robot實例相關,與repeat方法的邏輯無關。試圖通過通用簽名實施這種關係會產生問題而沒有任何好處。

事實上,已經有通用的工具允許重複。 E.g,你可以寫

EnhancedRobot e = new EnhancedRobot(); 
Collections.nCopies(3, e).forEach(EnhancedRobot::anyAction); 

EnhancedRobot e = new EnhancedRobot(); 
IntStream.range(0, 3).forEach(i -> e.anyAction()); 
相關問題