组合模式

例题:

商品类别树
+服装
+男装
-衬衣
-夹克
+女装
-裙子
-套装

特点:
1、有一个根节点
2、树枝节点
3、叶子结点
根节点和树枝节点都可以包含其他节点,统称为容器节点。
现在需要管理商品类别树,假设要求能实现输出如上商品类别树的结构功能,应该如何实现?
不带模式的解决方案:组合对象

import java.util.ArrayList;
import java.util.Collection;
 
class Leaf{
	private String name="";
	public Leaf(String name) {
		this.name=name;
	}
	public void printStuct(int d) {
		for(int i=0;i<d;i++)
			System.out.print(" ");
			System.out.println('-'+name);
	}
}
class Composite{
	private Collection<Composite>childComposite=new ArrayList<Composite>();
	private Collection<Leaf>childLeaf=new ArrayList<Leaf>();
	private String name="";
	public Composite(String name) {
		this.name=name;
	}
	public void addComposite(Composite c) {
		this.childComposite.add(c);
	}
	public void addLeaf(Leaf leaf) {
		this.childLeaf.add(leaf);
	}
	public void printStruct(int d) {
		for(int i=0;i<d;i++)
			System.out.print(" ");
		System.out.println('+'+name);
		for(Composite c:childComposite) {
			c.printStruct(d+2);
		}
		for(Leaf leaf:childLeaf) {
			leaf.printStuct(d+2);
		}
	}
}
public  class Main{
	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(0);
	}
}

结果为:
+服装
+男装
-衬衣
-夹克
+女装
-裙子
-套装

要处理的对象可以表示成一个树形结构,而要对树上的分支节点和叶子进行操作时,它能够提供一致的方式,而不用区分它是分支节点还是叶子。–抽象出共同基类Component,继承它产生叶子节点和容器节点。
改进方案

import java.util.ArrayList;
 
abstract class Component{
	protected String name;
	public Component(String name) {
		this.name=name;
	}
	public abstract void Add(Component component);
	public abstract void Remove(Component component);
	public abstract void printStruct(int component);
}
 
class Leaf extends Component{//叶子结点没有子节点
	public Leaf(String name) {
		super(name);
	}
	public void Add(Component component) {
		System.out.println("不能添加分支");
	}
	public void Remove(Component component) {
		System.out.println("不能删除分支");
	}
	public void printStruct(int d) {
		for(int i=0;i<d;i++)
			System.out.print(" ");
		System.out.println('-'+name);
	}
}
class Composite extends Component{
	private ArrayList<Component>components=new ArrayList<Component>();
	public Composite(String name) {
		super(name);
	}
	public void Add(Component component) {
		components.add(component);
	}
	public void Remove(Component component) {
		components.remove(component);
	}
	@Override
	public void printStruct(int d) {
		// TODO Auto-generated method stub
		for(int i=0;i<d;i++)
			System.out.print(" ");
		System.out.println('+'+name);
		for(Component component:components) {
			component.printStruct(d+2);
		}
	}
}
public  class Main{
	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.Add(c1);
				root.Add(c2);
				c1.Add(leaf1);
				c1.Add(leaf2);
				c2.Add(leaf3);
				c2.Add(leaf4);
				root.printStruct(0);
	}
}

结果为:
+服装
+男装
-衬衣
-夹克
+女装
-裙子
-套装

Component :是组合中的对象声明接口,在适当的情况下,实现所有类公有接口的默认行为。声明一个接口用于访问和管理Component子部件。
Leaf:在组合中表示叶子节点对象,叶子节点没有子节点。
Composite:定义分支节点行为,用来存储子部件,在Component接口中实现与 子部件有关的操作,如add和remove等。

import java.util.ArrayList;
 
abstract class Component{
	protected String name;
	public Component(String name) {
		this.name=name;
	}
	public abstract void Add(Component component);
	public abstract void Remove(Component component);
	public abstract void Display(int d);
}
 
class Leaf extends Component{//叶子结点没有子节点
	public Leaf(String name) {
		super(name);
	}
	public void Add(Component component) {
		System.out.println("不能添加一个树叶");
	}
	public void Remove(Component component) {
		System.out.println("不能添加一个树叶");
	}
	public void Display(int d) {
		for(int i=0;i<d;i++)
			System.out.print(" ");
		System.out.println('-'+name);
	}
}
class Composite extends Component{
	private ArrayList<Component>components=new ArrayList<Component>();
	public Composite(String name) {
		super(name);
	}
	public void Add(Component component) {
		components.add(component);
	}
	public void Remove(Component component) {
		components.remove(component);
	}
	@Override
	public void Display(int d) {
		// TODO Auto-generated method stub
		for(int i=0;i<d;i++)
			System.out.print(" ");
		System.out.println('+'+name);
		for(Component component:components) {
			component.Display(d+2);
		}
	}
}
 
public  class Main{
	public static void main(String[] args){
		//生成树根,根上长出两个树叶LeafA和LeafB
				Composite composite=new Composite("root");
				composite.Add(new Leaf("LeafA"));
				composite.Add(new Leaf("LeafB"));
		//根上长出分支CompositeX,分支上也有两叶LeafAx和LeafBx
				Composite compositex=new Composite("CompositeX");
				compositex.Add(new Leaf("LeafAx"));
				compositex.Add(new Leaf("LeafBx"));
				composite.Add(compositex);
				
				Composite compositeY=new Composite("CompositeXY");
				compositeY.Add(new Leaf("LeafAxY"));
				compositeY.Add(new Leaf("LeafBxY"));
				compositex.Add(compositeY);
				
				composite.Add(new Leaf("LeafAxYc"));
				Leaf leaf=new Leaf("LeafAxYd");
				composite.Add(leaf);
				composite.Remove(leaf);
				composite.Display(1);
	}
}
 

组合模式(Composite):有时又叫做部分-整体模式(Part-Whole ) ,将对象组合成树形结构以表示“部分-整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性(稳定):以一致的方式处理个别对象以及组合对象。

组合模式的优点:
1、定义了包含基本对象和组合对象的类层次结构
2、统一了组合对象和叶子对象
3、简化了客户端调用
4、更容易扩展
缺点:很难限制组合中的组件类型

组合模式的实现根据所实现接口的区别分为两种形式:安全方式和透明方式。
透明方式:

树可能有无数的分枝,可以反复用Composite实现树状结构。虽然树叶不可以再长分枝,但是Leaf类当中也有Add和Remove,这种方式叫做透明方式:在Component中 声明所有管理子对象的方法,其中包括Add、Remove以及Display等方法,这栏实现Component按口的所有子类都具各了Add的Remove以及Display等方法。
优点:叶节点和枝结点对于外界没有区别,他们具备完全一致的行为接口,客户端可以同等的对待所有的对象。
缺点:不够安全,因为树叶类对象和合成类对象在本质上是有区别的。树叶类对象不可能有下一个层次的对象,因比add ()、remove ()以及Display ()方法没有意义。

安全方法:
安全方式:在Component接口 中不去声明Add和Remove方法,那么子类的Leaf也就不需要去实现它,而是在合成类Composite (不是Component类)声明所有用来管理子类对象的方法。
优点:这样的做法是安全的做法,树叶类型的对象根本就有有管理子类对象的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。
缺点:不够透明,树叶类和合成类将具有不同的接口,客户端的调用需要做相应的判断,带来了不便

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值