设计模式学习之组合模式
来源:互联网 发布:钢铁力量里孔雀的数据 编辑:程序博客网 时间:2024/05/18 09:43
组合模式(Composite Pattern),是结构型模式之一。组合模式比较简单,它将一组相似的对象看作一个对象处理,并根据一个树状结构来组合对象,然后提供一个统一的方法去访问相应的对象,以此忽略掉对象与对象集合之间的差别。这个最典型的例子就是数据结构中的树,本篇博客我们就一起学习组合模式。
定义与使用场景
定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
使用场景:
1.表示对象的部分-整体层次结构时。
2.从一个整体中能够独立出部分模块或功能的场景。
UML图
(1)Component:抽象根节点,为组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。声明一个接口用于访问和管理Component的子节点。可在递归结构中定义一个接口,用于访问一个父节点,并在合适的情况下实现它。
(2)Composite:定义有子节点的那些枝干节点行为,存储子节点,在Component接口中实现与子节点有关的操作。
(3)Leaf:在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为。
(4)Client:通过Component接口操纵组合节点的对象。
组合模式模版代码
组合模式在实际使用中会有两种情况:安全的组合模式与透明的组合模式。上面的UML图属于安全组合模式的UML图。
安全组合模式
Component.class
public abstract class Component { public abstract void operation();}
Composite.class
public class Composite extends Component{ private ArrayList componentList = new ArrayList<>(); @Override public void operation() { for (Component component : componentList) { component.operation(); } } public void add(Component child) { componentList.add(child); } public void remove(Component child) { componentList.remove(child); } public Component getChild(int position) { return componentList.get(position); }}
Leaf.class
public class Leaf extends Component{ @Override public void operation() { }}
测试代码:
Composite root = new Composite();Leaf leaf1 = new Leaf();Composite branch = new Composite();root.add(leaf1);root.add(branch);Leaf leaf2 = new Leaf();branch.add(leaf2);root.operation();break;
可以发现,安全组合模式违反了 6 个设计模式原则中依赖倒置原则,客户端不应该直接依赖于具体实现,而应该依赖于抽象,既然是面向接口编程,就应该把更多的焦点放在接口的设计上,于是这样就产生了透明的组合模式。
透明的组合模式
透明的组合模式 uml 类图如下:
和安全的组合模式差异就是在将 Composite 的操作放到了 Component 中,这就造成 Leaf 角色也要实现 Component 中的所有方法。实现的代码做出相应改变:
Component.class
public interface Component { void operation(); void add(Component child); void remove(Component child); Component getChild(int position);}
Composite.class
public class Composite implements Component{ private ArrayList componentList = new ArrayList<>(); @Override public void operation() { Log.e("shawn", "this is composite " + this + " -------start"); for (Component component : componentList) { component.operation(); } Log.e("shawn", "this is composite " + this + " -------end"); } @Override public void add(Component child) { componentList.add(child); } @Override public void remove(Component child) { componentList.remove(child); } @Override public Component getChild(int position) { return componentList.get(position); }}
Leaf.class
public class Leaf implements Component { @Override public void operation() { Log.e("shawn", "this if leaf " + this); } @Override public void add(Component child) { throw new UnsupportedOperationException("leaf can't add child"); } @Override public void remove(Component child) { throw new UnsupportedOperationException("leaf can't remove child"); } @Override public Component getChild(int position) { throw new UnsupportedOperationException("leaf doesn't have any child"); }}
测试代码
Component root = new Composite();Component leaf1 = new Leaf();Component branch = new Composite();root.add(leaf1);root.add(branch);Component leaf2 = new Leaf();branch.add(leaf2);root.operation();
由于是在 Component 类中定义了所有的行为,所以客户端就不用直接依赖于具体 Composite 和 Leaf 类的实现,遵循了依赖倒置原则——依赖抽象,而不依赖具体实现。但是也违反了单一职责原则与接口隔离原则,让 Leaf 类继承了它本不应该有的方法,并且抛出了 UnsupportedOperationException ,这样做的目的就是为了客户端可以透明的去调用对应组件的方法,将枝干节点和子节点一视同仁。
另外,将 Component 写成一个虚基类,并且实现所有的 Composite 方法,而且默认都抛出异常,只让 Composite 去覆盖重写父类的方法,而 Leaf 类就不需要去实现 Composite 的相关方法,这么去实现当然也是可以的。
组合模式简单实现
以文件和文件夹这样的文件系统为例
文件和文件夹的抽象类:(Component)
public abstract class Dir { /** * 声明一个List成员变量来储存文件夹下的所有元素 */ protected List dirs = new ArrayList(); private String name; //当前文件或文件夹名 public Dir(String name) { this.name = name; } /** * 添加一个文件或文件夹 * * @param dir 文件或文件夹 */ public abstract void addDir(Dir dir); /** * 移除一个文件或文件夹 * * @param dir 文件或文件夹 */ public abstract void rmDir(Dir dir); /** * 清空文件夹下所有元素 */ public abstract void clear(); /** * 输出文件夹目录结构 */ public abstract void print(); /** * 获取文件夹下所有的文件或文件夹 * * @return 文件夹下所有的文件或文件夹 */ public abstract List getFiles(); /** * 获取文件或文件夹名 * * @return 文件或文件夹名 */ public String getName(){ return name; }}
表示文件夹的类:(Composite)
public class Folder extends Dir{ public Folder(String name) { super(name); } @Override public void addDir(Dir dir) { dirs.add(dir); } @Override public void rmDir(Dir dir) { dirs.remove(dir); } @Override public void clear() { dirs.clear(); } @Override public void print() { System.out.print(getName() + "("); Iterator iter = dirs.iterator(); while (iter.hasNext()) { Dir dir = iter.next(); dir.print(); if(iter.hasNext()){ System.out.print(", "); } } System.out.print(")"); } @Override public List getFiles() { return dirs; }}
表示文件夹的类:(Leaf)
public class File extends Dir{ public File(String name) { super(name); } @Override public void addDir(Dir dir) { throw new UnsupportedOperationException("文件对象不支持该操作!"); } @Override public void rmDir(Dir dir) { throw new UnsupportedOperationException("文件对象不支持该操作!"); } @Override public void clear() { throw new UnsupportedOperationException("文件对象不支持该操作!"); } @Override public void print() { System.out.print(getName()); } @Override public List getFiles() { throw new UnsupportedOperationException("文件对象不支持该操作!"); }}
客户类:
public class Client { public static void main(String[] args) { //构造一个目录对象表示C盘根目录 Dir diskC = new Folder("C"); //C盘根目录下有一个文件Log.txt diskC.addDir(new File("Log.txt")); //C盘根目录下有三个目录Windows、PerfLogs、Program File Dir dirWin = new Folder("Windows"); //Windows目录下有文件explorer.exe dirWin.addDir(new File("explorer.exe")); diskC.addDir(dirWin); //PerfLogs目录 Dir dirPer = new Folder("PerfLogs"); //PerfLogs目录下有文件null.txt dirPer.addDir(new File("null.txt")); diskC.addDir(dirPer); //Program File目录 Dir dirPro = new Folder("Program File"); //Program File目录下有文件ftp.txt dirPro.addDir(new File("ftp.txt")); diskC.addDir(dirPro); //打印出文件结构 diskC.print(); }}
Android源码中的模式实现
1.View和ViewGroup的嵌套组合
View和ViewGroup就是组合模式的实现,不过View的视图层级使用的是安全的组合模式。ViewGroup相对于View增加了addView、removeView、getChildAt等方法,想必大家也很熟悉。
总结
1.优点
(1)组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,他让高层模块忽略了层次的差异,方便对整个层次结构进行控制。
(2)简化了高层模块的代码。
(3)在组合模式中增加新的枝干构件和叶子构件都很方便,无须对现有类库进行修改,符合“开闭原则”。
(4)对树形结构的控制变得简单。
2.缺点
组合模式不容易限制组合中的构件。因为大多数情况下,它们都来自于相同的抽象层,此时,必须进行类型检查来实现,这个实现过程较为复杂。
- 设计模式学习笔记之组合模式
- 设计模式学习笔记之组合模式
- 设计模式学习之组合模式
- HeadFirst设计模式学习之组合模式
- 设计模式学习之路-组合模式
- 设计模式学习之组合模式
- 设计模式学习之组合模式
- 设计模式学习-----组合模式
- 设计模式学习--组合模式
- 设计模式学习--组合模式
- 设计模式学习-组合模式
- 设计模式学习--组合
- 设计模式之组合模式
- 设计模式之组合模式
- 设计模式之组合模式
- 设计模式之--组合模式
- 设计模式之组合模式
- 设计模式之组合模式
- [网络电话]Android Linphone开发实例
- eclipse创建maven项目(动态web工程)完整示例
- BZOJ4229: 选择
- DOM方式进行的XML文件、Document、String之间的相互转换
- AngularJS中【Error: [$rootScope:inprog]】的解决办法
- 设计模式学习之组合模式
- 代理技术简介(一):代理概述
- postman 谷歌浏览器安装postman插件
- Navigation bar 的注意事项
- java创建http接口,及调用
- 深入理解 CSS3 弹性盒布局模型
- ios 实现微信的非最近会话聊天界面的返回按钮
- opencv3.2+opencv_contrib+cmake
- Hbuilder-WebView相关