Java设计模式之合成模式
2018-01-13 17:39
393 查看
合成模式(composite pattern): 允许你将对象组合成树形结构来表现”整体/部分”层次结构. 合成模式能让客户以一致的方式处理个别对象以及对象组合.
合成模式的实现根据所实现接口的区别分为两种形式:安全式和透明式
角色说明:
抽象构件角色(Component):这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由数字构件对象给出。
叶子构件角色(Leaf):叶子对象是没有下级子对象的对象,定义出参加组合的原始对象行为。
树枝构件角色(Composite):代表参加组合的又下级子对象的对象,树枝构件类给出所有的管理子对象的方法,如add()、remove()和getChild()。
代码演示,抽象构件类:
树枝构件类:
叶子对象类:
测试类:
运行结果:
从类图和代码可以看出树枝构件类Composite都实现了addChild()、removeChild()和getChild()的方法,而叶子构件类则没有。这是安全式合成模式的特点,因为这个特点,客户端不可能调用到叶子构件类的这些方法,因为叶子构件类根本没有这些方法。
代码演示,抽象构件类:
树枝构件类:
叶子构件类:
测试类:
运行结果跟安全式的一样:
合成模式的安全式和透明式的选择
安全式:从客户端使用上看,安全式就不会发生误操作的可能。
透明式:从客户端使用上看,透明式是不用区分树枝对象和叶子对象。
合成模式的目的是让客户端不区分操作的是树枝对象还是叶子对象,而是统一的方式来操作。还有,对于安全式的实现,区分树枝和叶子对象的情况下,有时需要类型强转,这种体现就不安全了。所以综合考虑还是着重选择透明式合成模式的实现。当然这不是绝对的,还是要看具体需求的。
合成模式的实现根据所实现接口的区别分为两种形式:安全式和透明式
安全式合成模式的详解
类图:角色说明:
抽象构件角色(Component):这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由数字构件对象给出。
叶子构件角色(Leaf):叶子对象是没有下级子对象的对象,定义出参加组合的原始对象行为。
树枝构件角色(Composite):代表参加组合的又下级子对象的对象,树枝构件类给出所有的管理子对象的方法,如add()、remove()和getChild()。
代码演示,抽象构件类:
public interface Component { // 输出结构的名称 public void showStructure(String str); }
树枝构件类:
public class Composite implements Component { // 用来存储合成对象中的子构件对象 private List<Component> childComponents = new ArrayList<>(); // 合成对象的名称 private String name; public Composite(String name) { this.name = name; } /** * 增加一个子构件对象 * * @param child */ public void addChild(Component child) { childComponents.add(child); } /** * 移除一个子构件对象 * * @param index */ public void removeChild(int index) { childComponents.remove(index); } // 获取所有子构件对象 public List<Component> getChild() { return childComponents; } /** * 输出结构的名称 */ @Override public void showStructure(String str) { // 首先输出最高级构件 System.out.println(str + "●" + this.name); // 如果含有子构件,则输出 if (this.childComponents != null) { // 子构件向后缩进显示 str += " "; // 输出当前对象的子构件对象 for (Component c : childComponents) { // 递归输出每个子对象 c.showStructure(str); } } } }
叶子对象类:
public class Leaf implements Component { // 叶子对象的名称 private String name; public Leaf(String name) { this.name = name; } /** * 输出叶子构件的对象,叶子已经是最低级构件,所以只显示叶子名称就行 */ @Override public void showStructure(String str) { str += " "; System.out.println(str + "〉" + name); } }
测试类:
public class Client { public static void main(String[] args) { //声明最高级构件 Composite root = new Composite("宠物"); //子构件 Composite dog = new Composite("宠物狗"); Composite cat = new Composite("宠物猫"); //添加子构件 root.addChild(dog); root.addChild(cat); //声明叶子对象 Leaf leaf1 = new Leaf("柴犬"); Leaf leaf2 = new Leaf("二哈"); //添加叶子对象 dog.addChild(leaf1); dog.addChild(leaf2); Leaf leaf3 = new Leaf("波斯猫"); Leaf leaf4 = new Leaf("咖菲猫"); Leaf leaf5 = new Leaf("机器猫"); cat.addChild(leaf3); cat.addChild(leaf4); cat.addChild(leaf5); root.showStructure(""); System.out.println("===================="); //移除不是动物的猫 cat.removeChild(2); root.showStructure(""); } }
运行结果:
从类图和代码可以看出树枝构件类Composite都实现了addChild()、removeChild()和getChild()的方法,而叶子构件类则没有。这是安全式合成模式的特点,因为这个特点,客户端不可能调用到叶子构件类的这些方法,因为叶子构件类根本没有这些方法。
透明式合成模式的详解
类图:代码演示,抽象构件类:
public abstract class Component { // 输出构件的名称 public abstract void showStructure(String str); /** * 增加一个子构件对象 * * @param child */ public void addChild(Component child) { // 叶子构件类没有此功能,若缺省实现,则抛出异常 throw new UnsupportedOperationException("对象不支持此操作"); } /** * 移除一个子构件对象 * * @param index */ public void removeChild(int index) { // 叶子构件类没有此功能,若缺省实现,则抛出异常 throw new UnsupportedOperationException("对象不支持此操作"); } // 获取所有子构件对象 public List<Component> getChild() { // 叶子构件类没有此功能,若缺省实现,则抛出异常 throw new UnsupportedOperationException("对象不支持此操作"); } }
树枝构件类:
public class Composite extends Component { // 用来存储合成对象中的子构件对象 private List<Component> childComponents = new ArrayList<>(); // 合成对象的名称 private String name; public Composite(String name) { this.name = name; } /** * 增加一个子构件对象 * * @param child */ @Override public void addChild(Component child) { childComponents.add(child); } /** * 移除一个子构件对象 * * @param index */ @Override public void removeChild(int index) { childComponents.remove(index); } // 获取所有子构件对象 @Override public List<Component> getChild() { return childComponents; } /** * 输出结构的名称 */ @Override public void showStructure(String str) { // 首先输出最高级构件 System.out.println(str + "●" + this.name); // 如果含有子构件,则输出 if (this.childComponents != null) { // 子构件向后缩进显示 str += " "; // 输出当前对象的子构件对象 for (Component c : childComponents) { // 递归输出每个子对象 c.showStructure(str); } } } }
叶子构件类:
public class Leaf extends Component { // 叶子对象的名称 private String name; public Leaf(String name) { this.name = name; } /** * 输出叶子构件的对象,叶子已经是最低级构件,所以只显示叶子名称就行 */ @Override public void showStructure(String str) { str += " "; System.out.println(str + "〉" + name); } }
测试类:
public class Client { public static void main(String[] args) { //声明最高级构件 Component root = new Composite("宠物"); //子构件 Component dog = new Composite("宠物狗"); Component cat = new Composite("宠物猫"); //添加子构件 root.addChild(dog); root.addChild(cat); //声明叶子对象,这时不再区分Composite或Leaf对象了 Component leaf1 = new Leaf("柴犬"); Component leaf2 = new Leaf("二哈"); //添加叶子对象 dog.addChild(leaf1); dog.addChild(leaf2); Component leaf3 = new Leaf("波斯猫"); Component leaf4 = new Leaf("咖菲猫"); Component leaf5 = new Leaf("机器猫"); cat.addChild(leaf3); cat.addChild(leaf4); cat.addChild(leaf5); root.showStructure(""); System.out.println("===================="); //移除不是动物的猫 cat.removeChild(2); root.showStructure(""); } }
运行结果跟安全式的一样:
合成模式的安全式和透明式的选择
安全式:从客户端使用上看,安全式就不会发生误操作的可能。
透明式:从客户端使用上看,透明式是不用区分树枝对象和叶子对象。
合成模式的目的是让客户端不区分操作的是树枝对象还是叶子对象,而是统一的方式来操作。还有,对于安全式的实现,区分树枝和叶子对象的情况下,有时需要类型强转,这种体现就不安全了。所以综合考虑还是着重选择透明式合成模式的实现。当然这不是绝对的,还是要看具体需求的。
相关文章推荐
- java设计模式总结九:合成模式
- java设计模式---合成模式3
- java设计模式---合成模式3
- Java设计模式--合成模式
- Java设计模式-合成模式
- 设计模式之合成模式(Java语言描述)
- Java设计模式——合成/聚合复用原则
- 设计模式之合成模式(Java语言描述)
- java设计模式---合成模式
- Java设计模式笔记之合成模式
- Java设计模式——合成模式(Composite)
- 设计模式之合成模式(Java语言描述)
- java设计模式---合成模式
- Java设计模式百例 - 合成模式
- JAVA设计模式之合成模式
- Java设计模式百例 - 合成模式
- (八)Java设计模式之合成模式
- Java设计模式百例 - 合成模式