设计模式——组合模式

举报
yd_221104950 发表于 2020/12/03 01:14:40 2020/12/03
【摘要】 组合模式的定义 允许你将对象组合成树形结构来表现“整体/部分“层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。 讲解时,我们用图形界面上的菜单例子来举例说明。 组合模式的类图: 类图解析: Client:客户对象将使用组件接口访问菜单和菜单项 Component:提供了一组接口,让菜单项和菜单共同使用,并且提供了默认实现。但是我们希望由具体的菜单或菜...

组合模式的定义

允许你将对象组合成树形结构来表现“整体/部分“层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

讲解时,我们用图形界面上的菜单例子来举例说明。

组合模式的类图:
在这里插入图片描述
类图解析:
Client:客户对象将使用组件接口访问菜单和菜单项
Component:提供了一组接口,让菜单项和菜单共同使用,并且提供了默认实现。但是我们希望由具体的菜单或菜单项提供默认实现,因此我们使用了抽象类。
leaf:对于叶子节点(即菜单项)来说,父类Component中有很多方法是它不需要的,因此它只需要覆盖实现那些对它有意义的方法即可。
Composite:菜单也是只需要覆盖实现那些对它有意义的方法即可。

利用这个模式来统一处理个别对象和组合对象,意味着如果我们有了一个树形结构的菜单、子菜单和可能还带有菜单项的子菜单,那么任何一个菜单都是一种“组合”。因为它既可以包含其他菜单,也可以包含菜单项。个别对象只是菜单项——并未持有其他对象。

Component组件对象:MenuComponent
对每个方法都提供了默认的实现。因为有些方法只对菜单有意义,而有些只对菜单项有意义,默认实现是抛出UnsupportedOperationException 异常。这样,如果菜单项或菜单不支持某个操作,我们就不需要做什么事情了,直接继承默认实现就可以了。

public abstract class MenuComponent { public void operation(){ throw new UnsupportedOperationException(); } public void add(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public void remove(MenuComponent menuComponent){ throw new UnsupportedOperationException(); } public MenuComponent getChild(int position){ throw new UnsupportedOperationException(); } public String getName(){ throw new UnsupportedOperationException(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

实现leaf叶子节点:MenuItem
只实现对它有意义的方法

public class MenuItem extends MenuComponent{ private String name; public MenuItem(String name){ this.name = name; } @Override public String getName() { return name; } @Override public void operation() { System.out.println("   I am  "+getName()); }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

实现Composite组合菜单:Menu
只实现对它有意义的方法

import java.util.ArrayList;
import java.util.Iterator;

public class Menu extends MenuComponent { private ArrayList menuComponents = new ArrayList(); private String name; public Menu(String name){ this.name = name; } @Override public String getName() { return name; } @Override public void add(MenuComponent menuComponent) { menuComponents.add(menuComponent); } @Override public void remove(MenuComponent menuComponent) { menuComponents.remove(menuComponent); } @Override public MenuComponent getChild(int position) { return (MenuComponent)menuComponents.get(position); } @Override public void operation() { for (Object component:menuComponents) { MenuComponent component1 = ((MenuComponent)component); System.out.println(component1.getName()); component1.operation(); } }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

Client用户:

public class Client { private MenuComponent allMenus; public Client(MenuComponent allMenus){ this.allMenus = allMenus; } public void printMenu(){ allMenus.operation(); }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

测试

public class Main { public static void main(String[] args) { MenuComponent homeMenu = new Menu("Home"); MenuComponent viewMenu = new Menu("View"); MenuComponent editMenu = new Menu("Edit"); MenuComponent menus = new Menu("Menus"); menus.add(homeMenu); menus.add(viewMenu); menus.add(editMenu); homeMenu.add(new MenuItem("open")); homeMenu.add(new MenuItem("close")); homeMenu.add(new MenuItem("open as")); homeMenu.add(new MenuItem("new project...")); viewMenu.add(new MenuItem("Size")); viewMenu.add(new MenuItem("Canva")); editMenu.add(new MenuItem("Copy")); editMenu.add(new MenuItem("Past")); editMenu.add(new MenuItem("Cut")); Client client = new Client(menus); client.printMenu(); }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

测试结果:


Home
open I am  open
close I am  close
open as I am  open as
new project... I am  new project...
View
Size I am  Size
Canva I am  Canva
Edit
Copy I am  Copy
Past I am  Past
Cut I am  Cut



  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

组合模式以单一责任设计原则换取透明性。所谓透明性,就是通过让组件的接口同时包含一些管理子节点和叶子节点的操作,客户就可以将组合和叶节点一视同仁。即一个元素究竟是组合还是叶子节点,对客户是透明的。

为了保持透明性,组合内所有的对象都必须实现相同的接口,否则客户就必须操作哪个对象是用哪个接口,这就失去了组合模式的意义。很明显,这也意味着对象会拥有一些没有意义的方法调用。有时候你可让这样的方法不做事,返回null或者false,再激烈的做法就是直接抛出异常,像MenuComponent抽象类那样,直接抛出异常。

组合模式通常是用树形结构的,也就是一种层次结构。根就是顶层的组合,然后往下是它的孩子,最末端是叶节点。组件可以有一个指向父亲的指针,以便在游走时更容易。而且,如果引用某个孩子,你想从树形结果中删除这个孩子,你会需要父亲去删除它。一旦孩子有了指向父亲的引用,这做起来就很容易。

有时候,如果这个组合结构很复杂,或者遍历的代价太高,那么实现组合节点的缓存就很有帮助。比方说,如果你要不断遍历一个组合,而且它的每一个子节点都需要进行某些计算,那你就应该使用缓存来临时保存结果,省去遍历的开支。

最后,给大家送上组合模式的demo

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/88852027

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。