2017-04-11 110 views
1

所以我在嘗試創建一個類時可能會附加具有不同功能的子類並共享一個共同的祖先而沒有真正的大型層次樹。用於調用特定類的設計模式覆蓋特定的方法

我想要做的是nSkill接口的不同子類,它們被分配在一個列表中,然後調用執行。所有在SkillEvent(不在這裏)的子類。

我的問題在於SkillManager在這裏我就不如何區分哪些Skill應該打電話wheter這將是更大的影響只是創造Skill子類,並執行它的權利呢。

這是我Skill.class接口

public abstract class Skill 
{ 
    /** 
    * Private shortcut so this code doesn't have to be reused over and over to call 
    * for cooldowns on the skills 
    * @param dp player making the request 
    * @return if the command is available for use 
    */ 
    protected boolean canUse(DPlayer dp){ 
     String name = "skill_"+getName(); 
     if(!dp.getTag(name).isPresent()) 
      return false; 
     if(dp.getTag(name).get().getRemaining() > 0) { 
      dp.sendActionBarCooldown(ChatColor.AQUA + getName(), dp.getTag(name).get().getRemaining()); 
      return false; 
     } 
     return true; 
    } 
    /** 
    * Returns the name of this skills, this should also be the same 
    * name of the class implementing this interface for initialization 
    * propouses 
    * @return name of skills 
    */ 
    public abstract String getName(); 

    /** 
    * Executor to be implemented and replace/add functionality 
    */ 
    public abstract void execute(); 
} 

這是我SkillManager.class

public class SkillManager 
{ 
    private static final SkillManager instance = new SkillManager(); 
    private final List<Skill> SKILLS =new ArrayList<>(); 

    private SkillManager(){} 

    public static SkillManager get(){return instance;} 
    public void registerSkill(Skill s){ 
     SKILLS.add(s); 
    } 
    public void registerSkills(Skill... s){ 
     for(Skill skill : s){ 
      SKILLS.add(skill); 
     } 
    } 
    public void unregisterSkill(String name){ 
     for(Skill skill : SKILLS){ 
      if(skill.getName().equalsIgnoreCase(name)){ 
       SKILLS.remove(skill); 
      } 
     } 
    } 
    public void callEvent(Skill skill) { 
     skill.execute(); 
    } 

} 

這是Sneak.class示例實現

public class Sneak extends Skill { 

    @Override 
    public String getName() { 
     return "Sneak"; 
    } 

    @Override 
    public void onSneak(DPlayer dp, PlayerToggleSneakEvent event){ 
     if(dp.getTag("skills_sneak").isPresent()){ 
//DO STUFF 
     } 
    } 
} 

感謝您的幫助。 編輯: Event對象來自不是我的實現,幷包含有關所述事件的數據的API調用 編輯2:添加流程圖。紅色是我編碼的部分。藍色是結構的一部分,我使用 Flow Diagram

+1

與您的問題沒有直接關係,但在您的示例中,沒有必要使'List SKILLS'成爲靜態成員。 –

+0

謝謝@ChristopheWeis我完全錯過了 – MartinStone

回答

1

有你的OOP代碼有兩個主要問題:

  • callEvent不依賴於你的所有事件的實現獨特的抽象方法,迫使你檢查對象的類型以調用正確的方法。
  • 您將事件實例的強制轉換作爲參數發送給自己,從而在調用者中使用您所有的事件類型創建無用的依賴關係。

使用指令設計模式;而不是有onSneak()onBreak()等,只是使用普通的​​方法。在你的Skill.class中,聲明execute爲抽象方法,迫使你在所有extends中編寫它的實現。它將被用來觸發事件。 callEvent()現在只需要一行代碼:event.execute(dp);

您不應該將事件作爲參數發送給自己,因爲作爲一個實例,它可以保存自己的屬性並且已經知道自己。

PS:您可以在您的問題中將此優化稱爲,但這不是真正的優化。修復這個架構很難讓你的代碼更快。另一方面,它將使讀取,維護和更可靠更加容易。 請注意過早的代碼優化。

+0

我已經使'技巧',使'執行(SkillCommand)'是抽象的。 'SkillComand'是一個封裝了'DPlayer'和'Event'對象的類。然而,我在'callEvent(SkillCommand)'處再次遇到問題,我不知道如何從HashMap中找到我需要調用的正確對象並調用它們,這意味着所有的技能都將在1個玩家上執行。 請閱讀我的編輯我想你錯過了代碼中的'Event'功能。 – MartinStone

+0

將所有事件發送給所有技能,並讓技能選取他們想要處理的事件。 –

+0

這會使每個技能都變得巨大嗎? 我編輯了我目前使用的代碼。我是否應該在每項技能上實施檢查,每次調用1項技能實際上是調用50次以上,而不僅僅是做一次檢查,然後什麼都不做? – MartinStone