• 设计模式16---设计模式之组合模式(Composite)(行为型)


    1.场景模拟

    使用软件模拟大树的根节点和树枝节点和叶子节点
    抽象为两类,容器节点和叶子节点

    2.不用模式的解决方案

    package demo14.composite.example1;
    import java.util.*;
    
    
    /**
     * 组合对象,可以包含其它组合对象或者叶子对象
     */
    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);
    		}
    	}
    }
    ***********************************************************************************************
    package demo14.composite.example1;
    /**
     * 叶子对象
     */
    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);
    	}
    }
    ***************************************************************************************************
    package demo14.composite.example1;
    
    
    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("");
    	}
    }

    3.问题所在

    大家很容易就发现了一个问题:那就是必须区分叶子节点和容器节点,无论是客户端还是内部都要区分,那么这样就会使得程序变得复杂,对于功能的扩展也不方便,而且要知道两个类才行,那么我们能不能把他整合成一个类呢,让客户端如下显示呢?答案是可以的。

    package demo14.composite.example2;
    
    
    public class Client {
    	public static void main(String[] args) {
    		//定义多个Composite对象
    		Component root = new Composite();
    		Component c1 = new Composite();
    		Component c2 = new Composite();
    		//定义多个叶子对象
    		Component leaf1 = new Leaf();
    		Component leaf2 = new Leaf();
    		Component leaf3 = new Leaf();
    		
    		//组和成为树形的对象结构
    		root.addChild(c1);
    		root.addChild(c2);
    		root.addChild(leaf1);
    		
    		c1.addChild(leaf2);
    		c2.addChild(leaf3);
    		
    		//操作Component对象
    		Component o = root.getChildren(1);
    		System.out.println(o);
    	}
    }

    4.解决方案的示例代码

    很明显,上述客户端的代码就顺眼多了,那么我们改如何实现呢?

    4.1首先看结构图

     

    4.2组合模式定义

    将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

    4.3示例代码如下

    package demo14.composite.example2;
    
    
    /**
     * 抽象的组件对象,为组合中的对象声明接口,实现接口的缺省行为
     */
    public abstract class Component {
    	/**
    	 * 示意方法,子组件对象可能有的功能方法
    	 */
    	public abstract void someOperation();
    
    
    	/**
    	 * 向组合对象中加入组件对象
    	 * 
    	 * @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("对象不支持这个功能");
    	}
    }
    **********************************************************************
    package demo14.composite.example2;
    
    
    import java.util.*;
    
    
    /**
     * 组合对象,通常需要存储子对象,定义有子部件的部件行为,
     * 并实现在Component里面定义的与子部件有关的操作
     */
    public class Composite extends Component {
    	/**
    	 * 用来存储组合对象中包含的子组件对象
    	 */
    	private List<Component> childComponents = null;
    
    
    	/**
    	 * 示意方法,通常在里面需要实现递归的调用
    	 */
    	public void someOperation() {		
    		if (childComponents != null){
    			for(Component c : childComponents){
    				//递归的进行子组件相应方法的调用
    				c.someOperation();
    			}
    		}
    	}
    	public void addChild(Component child) {
    		//延迟初始化
    		if (childComponents == null) {
    			childComponents = new ArrayList<Component>();
    		}
    		childComponents.add(child);
    	}
    
    
    	public void removeChild(Component child) {
    		if (childComponents != null) {
    			childComponents.remove(child);
    		}
    	}
    
    
    	public Component getChildren(int index) {
    		if (childComponents != null){
    			if(index>=0 && index<childComponents.size()){
    				return childComponents.get(index);
    			}
    		}
    		return null;
    	}
    }
    **********************************************************************
    package demo14.composite.example2;
    
    
    /**
     * 叶子对象,叶子对象不再包含其它子对象
     */
    public class Leaf extends Component {
    	/**
    	 * 示意方法,叶子对象可能有自己的功能方法
    	 */
    	public void someOperation() {
    		// do something
    	}
    }
    **********************************************************************
    package demo14.composite.example2;
    
    
    public class Client {
    	public static void main(String[] args) {
    		//定义多个Composite对象
    		Component root = new Composite();
    		Component c1 = new Composite();
    		Component c2 = new Composite();
    		//定义多个叶子对象
    		Component leaf1 = new Leaf();
    		Component leaf2 = new Leaf();
    		Component leaf3 = new Leaf();
    		
    		//组和成为树形的对象结构
    		root.addChild(c1);
    		root.addChild(c2);
    		root.addChild(leaf1);
    		
    		c1.addChild(leaf2);
    		c2.addChild(leaf3);
    		
    		//操作Component对象
    		Component o = root.getChildren(1);
    		System.out.println(o);
    	}
    }

    5.组合模式解决场景模拟

    代码的修改量并不大,跟示例代码差不多

    5.1结构图如下

     

    5.2代码如下(基本上同示例代码差不多,就不过多介绍了,注释非常清楚)

    package demo14.composite.example3;
    
    
    /**
     * 抽象的组件对象
     */
    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("对象不支持这个功能");
    	}
    }
    *********************************************************************************************
    package demo14.composite.example3;
    import java.util.*;
    
    
    /**
     * 组合对象,可以包含其它组合对象或者叶子对象
     */
    public class Composite extends Component{
    	/**
    	 * 用来存储组合对象中包含的子组件对象
    	 */
    	private List<Component> childComponents = null;
    	/**
    	 * 组合对象的名字
    	 */
    	private String name = "";
    	/**
    	 * 构造方法,传入组合对象的名字
    	 * @param name 组合对象的名字
    	 */
    	public Composite(String name){
    		this.name = name;
    	}
    	
    	public void addChild(Component child) {
    		//延迟初始化
    		if (childComponents == null) {
    			childComponents = new ArrayList<Component>();
    		}
    		childComponents.add(child);
    	}
    	/**
    	 * 输出组合对象自身的结构
    	 * @param preStr 前缀,主要是按照层级拼接的空格,实现向后缩进
    	 */
    	public void printStruct(String preStr){
    		//先把自己输出去
    		System.out.println(preStr+"+"+this.name);
    		//如果还包含有子组件,那么就输出这些子组件对象
    		if(this.childComponents!=null){
    			//然后添加一个空格,表示向后缩进一个空格
    			preStr+=" ";		
    			//输出当前对象的子对象了
    			for(Component c : childComponents){
    				//递归输出每个子对象
    				c.printStruct(preStr);
    			}
    		}
    	}
    }
    **********************************************************************************************
    package demo14.composite.example3;
    
    
    /**
     * 叶子对象
     */
    public class Leaf extends Component {
    	/**
    	 * 叶子对象的名字
    	 */
    	private String name = "";
    
    
    	/**
    	 * 构造方法,传入叶子对象的名字
    	 * 
    	 * @param name
    	 *        叶子对象的名字
    	 */
    	public Leaf(String name) {
    		this.name = name;
    	}
    
    
    	/**
    	 * 输出叶子对象的结构,叶子对象没有子对象,也就是输出叶子对象的名字
    	 * 
    	 * @param preStr
    	 *        前缀,主要是按照层级拼接的空格,实现向后缩进
    	 */
    	public void printStruct(String preStr) {
    		System.out.println(preStr + "-" + name);
    	}
    }
    ********************************************************************************************
    package demo14.composite.example3;
    
    
    public class Client {
    	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("");
    	}
    }

    6.组合模式讲解

    6.1要点

    目的:客户端不再区分叶子节点和组合对象
    关键点:设计一个抽象的组合对象

    6.2组合模式本质

    统一叶子对象和组合对象

  • 相关阅读:
    PHP中cookie和session
    php冒泡排序 快速 选择 插入 排序
    闲置U盘变身最强大路由器
    网络工程师(CCIE)面试题大搜集
    华为与思科交换机的差别及需要注意到地方
    CISCO VSS与HSRP、VRRP、RSTP对比分析
    BNC接口、RJ45、RJ48之间区别
    CCIE找工作的七大职业走向(转载)
    2层交换机与3层交换机之间到底有什么差别!
    CISCO 6500系列交换机  简介
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3223831.html
Copyright © 2020-2023  润新知