2017-05-04 20 views
0

嗨我正在使用複合模式。我將使用Head First Design Pattern的這個例子來解釋https://github.com/bethrobson/Head-First-Design-Patterns/tree/master/src/headfirst/designpatterns/composite/menuiterator如何自動填充複合模式,多態?

想象一下,每個菜單和子菜單都有一個Id來標識,它的長度是10。 像這樣

0100000000 menu_1 
0101000000 menu_1's subMenu_1 
0102000000 menu_1's subMenu_2 
0102010000  subMenu_2's subMenu_3 
0200000000 menu_2 

而且我隨意什麼是菜單項,但它有一個ID,這是它所屬的菜單ID其中。例如

0101000000 menuItem_1 
0200000000 menuItem_2 

所以菜單項1屬於菜單1的子菜單1和菜單項2屬於菜單2.

這將是編碼這樣的。

menu_1.add(subMenu_1); 
    subMenu_1.add(menuItem_1); 

menu_2.add(menuItem_2); 

現在我該如何填充菜單?

我在做什麼,因爲我只得到MenuItems,是我削減Id來確定它屬於哪裏。 例如你可以看到有兩個菜單,菜單1(0100000000)和菜單2(0200000000),所以我必須剪掉前2個字符串。

我編碼是這樣的:

class AllMenus implements MenuComponent { 

    MenuComponent menu_1 
    MenuComponent subMenu_1 
    MenuComponent subMenu_2 
    MenuComponent subMenu_3 
    MenuComponent menu_2 

    @Override 
    add(MenuComponent menu) { 

     if(menu instanceof Menu) { 

     super.add(menu) 

     } else if(menu instanceof MenuItem) { 

     String subId = menuItem.getId().subString(0,2) 

     if(subId.equals("01")) { 

      if(menu_1 == null) { 
       menu_1 = new Menu(); 
       add(menu_1); 
      } 

      subId = menuItem.getId().subString(0,4); 

      if(subId.equals("0101")) { 

       if(subMenu_1 == null) { 
        subMenu_1 = new Menu(); 
        menu_1.add(subMenu_1); 
       } 
       subMenu_1.add(menuItem); 

      } else if(subId.equals("0102")) { 

       if(subMenu_2 == null) { 
        subMenu_2 = new Menu(); 
        menu_1.add(subMenu_2); 
       } 

       subId = menuItem.getId().subString(0,6); 

       if(subId.equals("010201")) { 

        if(subMenu_3 == null) { 

        subMenu_3 = new Menu(); 
        subMenu_2.add(subMenu_3); 

        } 
        subMenu_3.add(menuItem); 
       } 

      } 


     } else if(subId.equals("02") { 

      if(menu_2 == null) { 

       menu_2 = new Menu(); 
       add(menu_2); 
      } 
      menu_2.add(menuItem); 
     } 
     } 
    } 
} 

這是每一個菜單項我得到。所以你可以看到這個代碼只需要四個菜單,想象成千上萬的菜單,它怎麼會變得更好? 我已經讀過,我應該使用多態性重複的東西,但我不知道在這種情況下。

+0

如果你給出以大寫字母開頭的變量名稱,它真的讓Java人感到困惑。 'NamesStartingWithAcital'保留給類名稱。建議你解決這個問題;如果我們可以在不使頭痛的情況下查看代碼,那麼您更有可能得到答案。 – slim

+0

你還可以更詳細地解釋十位數字應該如何解釋?我相信我沒有看到這種模式。 – slim

+0

@slim嗨模式是當我使用add()方法。在後面有一個迭代器,否則,MenuItem和Menu實現MenuComponent,十位數字是menuItem所屬的地方。什麼是常量菜單,但不是菜單項,但要確定屬於即時通訊使用subString來確定它必須去menuItem添加到一些menu.edited變量名稱的方式 – MarioK17

回答

0

如果我正確理解你的問題,我認爲你的代碼中最終結構的假設太多了。

一般而言,代碼中的數字文字應該被懷疑 - 例如,

if(subId.equals("010201") 

...因爲它看起來像配置,而不是代碼。當然,在代碼中放置「配置」是很好的做法,有時候這種配置是程序代碼而不是XML/CSV/JSON /等。 - 但即使如此,在「配置」類和「代碼」類之間進行邏輯分隔也是很好的做法。例如你的「配置」類可能只包含一個返回字符串數組的方法:

public class MenuConfig() { 
    public String[][] configs() { 
     return new String[][] { 
      new String[] {"0100000000", "Main menu"}, 
      new String[] {"0101000000", "Settings"}, 
      new String[] {"0101010000", "Look and feel"}, 
      new String[] {"0102000000", "My account"}, 
      // etc. 
     } 
    } 
} 

你希望創建子菜單樹 - 尋找靈感的代碼操作樹(例如二叉樹) - 看看代碼是多麼簡單,以及除了每個節點有零個或多個子節點的事實之外,它不會做出假設。

你已經在使用多態 - 你的菜單和子菜單符合一個通用的類型(我不能告訴你的代碼是否它們都具有相同的具體類型,但是原則上我可能希望你有多種類型的類實現MenuComponent

你的代碼來處理一個菜單隻需要解析ID的工作在哪裏它應該去的,然後找到它需要去的地方,然後將其插入:

(我提出的ID與連字符,使其更易於閱讀)

// split "01-02-03-00-00" into [1,2,3] -- ignoring trailing zeros 
List<Integer> path = parse(currentMenu.getId()); 

MenuComponent m = rootMenuComponent; 
while(path.size() > 1) { 
    m = m.getSubMenu(path.remove(0)); 
} 
m.add(path.remove(0), currentMenu()); 

這個簡單的算法假定菜單以正確的順序添加的 - 這就是你必須01-02-01-00-00之前已經處理​​,否則你會得到一個空指針。

如果你不能忍受這種限制,你需要定義可能發生的事情,並決定如何處理它。

    與您現有的方案
  • 其實,排序鍵按字母順序應該是足夠
  • 如果他們只是要出來序,你可以把菜單的待辦事項列表添加作爲一個隊列。如果某個特定項目尚未添加,請將其放到隊列的後面,並在處理剩下的項目後重試。
  • 如果你不想明確定義中間菜單,那麼當m.getSubMenu(subMenuNum)返回null(因爲你已經隱式地「定義」它在路徑的中間),你需要創建一個缺少的菜單點。
  • 如果您希望可以不止一次地定義相同的菜單(也許隱式和顯式地),那麼您需要MenuComponent.add()來處理這種情況,根據您的要求合併或覆蓋。

組裝像這樣的節點的圖形是Spring依賴注入的功能 - 當依賴性以任意順序定義時,按順序構建圖形。如果你的目標是學習,不斷建立你自己的。如果你只是想建立一個菜單組合,考慮使用Spring(或其他一些DI框架)。