組合模式容許用戶將對象組合成樹形結構來表現「總體/部分」的層次結構,從而可以以一致的方式處理單個對象以及對象組合。根據這個定義,首先可以想到的就是軟件的菜單,一個菜單能夠包含菜單項(菜單項是指再也不包含其餘內容的菜單條目),也能夠包含帶有其餘菜單項的菜單,所以使用組合模式描述菜單就很恰當,咱們的需求是針對一個菜單,打印出其包含的全部菜單以及菜單項。ide
首先,無論是菜單仍是菜單項,都應該繼承自統一的接口,這裏姑且將這個統一的接口稱爲菜單組件,其定義以下:測試
1 public abstract class MenuComponent { 2 public void add(MenuComponent menuComponent){ 3 throw new UnsupportedOperationException(); 4 } 5 6 public void remove(MenuComponent menuComponent){ 7 throw new UnsupportedOperationException(); 8 } 9 10 public MenuComponent getChild(int i){ 11 throw new UnsupportedOperationException(); 12 } 13 14 public String getName(){ 15 throw new UnsupportedOperationException(); 16 } 17 18 public String getDescription(){ 19 throw new UnsupportedOperationException(); 20 } 21 22 public void print(){ 23 throw new UnsupportedOperationException(); 24 } 25 }
這裏選擇抽象類來實現MenuComponent,是由於須要對一些方法給出默認實現,如此一來,Menu和MenuItem類就能夠只覆蓋本身感興趣的方法,而不用搭理不須要或者不感興趣的方法,舉例來講,Menu類能夠包含子菜單,所以須要覆蓋add()、remove()、getChild()方法,可是MenuItem就不該該有這些方法。這裏給出的默認實現是拋出異常,你也能夠根據本身的須要改寫默認實現。this
接下來定義菜單類Menu:spa
1 public class Menu extends MenuComponent{ 2 private List<MenuComponent> menuComponentList; 3 private String name; 4 private String descrition; 5 6 public Menu(String name, String description){ 7 this.name = name; 8 this.descrition = description; 9 menuComponentList = new ArrayList<>(); 10 } 11 12 @Override 13 public void add(MenuComponent menuComponent){ 14 menuComponentList.add(menuComponent); 15 } 16 17 @Override 18 public void remove(MenuComponent menuComponent){ 19 menuComponentList.remove(menuComponent); 20 } 21 22 @Override 23 public MenuComponent getChild(int i){ 24 return menuComponentList.get(i); 25 } 26 27 @Override 28 public String getName() { 29 return name; 30 } 31 32 @Override 33 public String getDescription(){ 34 return descrition; 35 } 36 37 @Override 38 public void print(){ 39 System.out.println(getName() + ", " + getDescription()); 40 Iterator iterator = menuComponentList.iterator(); 41 while(iterator.hasNext()){ 42 MenuComponent menuComponent = (MenuComponent) iterator.next(); 43 menuComponent.print(); 44 } 45 } 46 }
Menu類應該覆蓋本身感興趣的方法,實際上這裏它覆蓋了父類的全部方法,這樣作的緣由僅僅是由於抽象類中的全部方法都是該類須要的,假設某一天咱們在MenuComponent裏面增長了color()方法,該方法只針對菜單項顯示灰色底色,那麼Menu累就不該該覆蓋color()方法了。code
讓咱們接着來實現MenuItem:對象
1 public class MenuItem extends MenuComponent{ 2 private String name; 3 private String descrition; 4 5 public MenuItem(String name, String descrition){ 6 this.name = name; 7 this.descrition = descrition; 8 } 9 10 @Override 11 public String getName() { 12 return name; 13 } 14 15 @Override 16 public String getDescription(){ 17 return descrition; 18 } 19 20 @Override 21 public void print(){ 22 System.out.println(getName() + ", " + getDescription()); 23 } 24 }
MenuItem只覆蓋了getName()、getDescription()、print()方法,由於其餘的方法對該類並不適用。blog
如今能夠寫個測試類看一下組合模式在菜單上面的表現了:繼承
1 public class MenuComponentTest { 2 public static void main(String[] args){ 3 MenuComponentTest test = new MenuComponentTest(); 4 MenuComponent allMenu = test.createMenu(); 5 allMenu.print(); 6 } 7 8 public MenuComponent createMenu(){ 9 MenuComponent fileMenu = new Menu("文件", "文件相關選項"); 10 fileMenu.add(new MenuItem("設置", "能夠更改一些設置項")); 11 fileMenu.add(new MenuItem("保存", "保存全部文件")); 12 13 MenuComponent saveAsMenu = new Menu("另存爲", "另存爲其餘一些格式"); 14 saveAsMenu.add(new MenuItem("PDF", "另存爲PDF格式")); 15 saveAsMenu.add(new MenuItem("docx","另存爲docx格式")); 16 fileMenu.add(saveAsMenu); 17 18 MenuComponent helpMenu = new Menu("幫助","一些輔助項"); 19 helpMenu.add(new MenuItem("關於咱們","軟件製做方的一些消息")); 20 helpMenu.add(new MenuItem("幫助中心","電話和郵箱諮詢")); 21 22 MenuComponent allMenu = new Menu("全部菜單","包含全部菜單的菜單"); 23 allMenu.add(fileMenu); 24 allMenu.add(helpMenu); 25 26 return allMenu; 27 } 28 }
打印結果爲(沒有縮進因此稍微醜了一點):接口
全部菜單, 包含全部菜單的菜單
文件, 文件相關選項
設置, 能夠更改一些設置項
保存, 保存全部文件
另存爲, 另存爲其餘一些格式
PDF, 另存爲PDF格式
docx, 另存爲docx格式
幫助, 一些輔助項
關於咱們, 軟件製做方的一些消息
幫助中心, 電話和郵箱諮詢
最後回顧一下這個菜單的例子,類之間的關係以下:ip