组合模式(Composite)
@@@模式定义:
将对象组合成树型结构以表示“部分-整体”的层次结构。
组合模式使得用户对单个对象和组合对象的使用具有一致性。
@@@练习示例:
商品类别树
@@@示例代码:
<不用模式>
\product\Leaf.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package product; /** * 叶子对象 */ public class Leaf { /** * 叶子对象的名字 */ private String name = ""; /** * 构造方法,传入叶子对象的名字 * @param name 叶子对象的名字 */ public Leaf(String name) { this.name = name; } /** * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字 * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进 */ public void printStruct(String preStr) { System.out.println(preStr + "-" + name); } }
\product\Composite.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package product; import java.util.ArrayList; import java.util.Collection; /** * 组合对象,可以包含其他组合对象或者叶子对象 */ public class Composite { /** * 用来记录包含的其他组合对象 */ private Collection<Composite> childComposite = new ArrayList<Composite>(); /** * 用来记录包含的其他叶子对象 */ private Collection<Leaf> childLeaf = new ArrayList<Leaf>(); /** * 组合对象的名字 */ private String name = ""; /** * 构造方法,传入组合对象的名字 * @param name 组合对象的名字 */ public Composite(String name) { this.name = name; } /** * 向组合对象加入被它包含的其他组合对象 * @param c 被它包含的其他组合对象 */ public void addComposite(Composite c) { this.childComposite.add(c); } /** * 向组合对象加入被它包含的叶子对象 * @param leaf 被它包含的叶子对象 */ public void addLeaf(Leaf leaf) { this.childLeaf.add(leaf); } /** * 输出组合对象自身的结构 * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进 */ public void printStruct(String preStr) { // 先把自己输出去 System.out.println(preStr + "" + this.name); // 然后添加一个空格,表示向后缩进一个空格,输出自己包含的叶子对象 preStr += " "; for(Leaf leaf : childLeaf) { leaf.printStruct(preStr); } // 输出当前对象的字对象 for(Composite c : childComposite) { // 递归输出每个子对象 c.printStruct(preStr); } } }
\user\Client.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user; import product.Composite; import product.Leaf; public class Client { public static void main(String[] args) { // 定义所有的组合对象 Composite root = new Composite("服装"); Composite c1 = new Composite("男装"); Composite c2 = new Composite("女装"); // 定义所有的叶子对象 Leaf leaf1 = new Leaf("衬衣"); Leaf leaf2 = new Leaf("夹克"); Leaf leaf3 = new Leaf("裙子"); Leaf leaf4 = new Leaf("套装"); // 按照树的结构来组合组合对象和叶子对象 root.addComposite(c1); root.addComposite(c2); c1.addLeaf(leaf1); c1.addLeaf(leaf2); c2.addLeaf(leaf3); c2.addLeaf(leaf4); // 调用根对象的输出功能来输出整棵树 root.printStruct(""); } }
<问题描述>
必须区分组合对象和叶子对象,并进行有区别的对待;
<使用模式>
\pattern\Component.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; /** * 抽象的组件对象 */ public abstract class Component { /** * 输出组件自身的名称 */ public abstract void printStruct(String preStr); /** * 向组合对象中加入组件对象 * @param child 被加入组合对象中的组件对象 */ public void addChild(Component child) { throw new UnsupportedOperationException("不支持该功能"); } /** * 从组合对象中移出某个组件对象 * @param child 被移出的组件对象 */ public void removeChild(Component child) { throw new UnsupportedOperationException("不支持该功能"); } /** * 返回某个索引对应的组件对象 * @param index 需要获取的组件对象的索引,索引从0开始 * @return 索引对应的组件对象 */ public Component getChildren(int index) { throw new UnsupportedOperationException("不支持该功能"); } }
\pattern\Leaf.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; /** * 叶子对象 */ public class Leaf extends Component { /** * 叶子对象的名字 */ private String name = ""; /** * 构造方法,传入叶子对象的名字 * @param name 叶子对象的名字 */ public Leaf(String name) { this.name = name; } /** * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字 * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进 */ @Override public void printStruct(String preStr) { System.out.println(preStr + "-" + name); } }
\pattern\Composite.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern; import java.util.ArrayList; import java.util.List; /** * 组合对象,可以包含其他组合对象或者叶子对象 */ public class Composite extends Component { /** * 用来存储组合对象中包含的子组件对象 */ private List<Component> childComonents = null; /** * 组合对象的名字 */ private String name = ""; /** * 构造方法,传入组合对象的名字 * @param name 组合对象的名字 */ public Composite(String name) { this.name = name; } @Override public void addChild(Component child) { // 延迟初始化 if (childComonents == null) { childComonents = new ArrayList<Component>(); } childComonents.add(child); } /** * 输出组合对象自身的结构 * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进 */ @Override public void printStruct(String preStr) { // 先把自己输出去 System.out.println(preStr + "" + this.name); // 如果还包含有子组件,那么就输出这些子组件对象 if (this.childComonents != null) { // 添加一个空格,表示向后缩进一个空格 preStr += " "; // 输出当前对象的子对象 for (Component c : childComonents) { // 递归输出每个子对象 c.printStruct(preStr); } } } }
\user\CilentPattern.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user; import pattern.Component; import pattern.Composite; import pattern.Leaf; public class CilentPattern { public static void main(String[] args) { // 定义所有的组合对象 Component root = new Composite("服装"); Component c1 = new Composite("男装"); Component c2 = new Composite("女装"); // 定义所有的叶子对象 Component leaf1 = new Leaf("衬衣"); Component leaf2 = new Leaf("夹克"); Component leaf3 = new Leaf("裙子"); Component leaf4 = new Leaf("套装"); // 按照树的结构来组合组合对象和叶子对象 root.addChild(c1); root.addChild(c2); c1.addChild(leaf1); c1.addChild(leaf2); c2.addChild(leaf3); c2.addChild(leaf4); // 调用根对象的输出功能来输出整棵树 root.printStruct(""); } }
@@@模式的实现:
1. 有“安全性”和“透明性”两种实现方式;
@@@模式的优点:
1. 定义了包含基本对象和组合对象的类层次结构;
2. 统一了组合对象和叶子对象;
3. 简化了客户端调用;
4. 更容易扩展;
@@@模式的缺点:
1. 很难限制组合中的组件类型;
@@@模式的本质:
统一叶子对象和组合对象。
@@@模式体现的设计原则:
NA