15.组合模式(Composite Pattern)

1.定义

将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
组合模式又叫做树形模式。其在项目开发中涉及树的结构都会想到组合模式。

 

2.引子

我们计算机的文件系统就是一个典型组合模式的使用,文件分为两种:一、文件夹,二、文件。其中文件夹可以包含文件,也可以包含子文件夹。如果我们用资源管理器打开某个文件夹,发现它展开在左侧的是一个树形结构。
而我们的组合模式就是为了解决这种树形结构的递归问题。这种问题在生活中很常见,比如某个机关的人事关系图。

 

 

3.组合模式的使用场景

  • 维护和展示部分-整体关系的场景,比如树形菜单、文件和文件夹管理。
  • 从一个整体中能独立出部分模块或功能的场景。

下面以人事关系的代码为例讲解该模式的实现:

 

package _15CompositePattern;

/**
 * 某公司的抽象员工类
 * 无论领导或者普通职员都有的属性
 */
public abstract class Corp {

	private String name;// 姓名
	private int salary;// 薪水
	
	public Corp(String name, int salary)
	{
		this.name = name;
		this.salary = salary;
	}
	
	public void prinInfo()
	{
		System.out.println("Name: " + name + ", Salary:" + salary);
	}
	
}
 
package _15CompositePattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 领导类
 * 出了拥有普通员工的权限,偶尔还要关怀一下下属,要不他们不干活
 */
public class Branch extends Corp {

	// 手下的所有下属
	private List<Corp> subList = new ArrayList<Corp>();
	
	public Branch(String name, int salary) {
		super(name, salary);
	}
	
	// 增加一个下属,这个下属可能是小兵,也可能是领导(当然职位比我低)
	public void addSub(Corp sub) {
		subList.add(sub);
	}

	// 获得我的所有下属
	public List<Corp> getSubList() {
		return subList;
	}
}
 
package _15CompositePattern;

/**
 * 普通员工类
 * 除了自己不需要关心任何别人的事情
 */
public class Leaf extends Corp {

	public Leaf(String name, int salary) {
		super(name, salary);
	}
}
 
package _15CompositePattern;

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Corp bossCorp = new Branch("张三", 100000);
		// 设置了张三是一个boss,给他加小弟的代码就不详细写了
		// ...
		printAllCorpInfo(bossCorp);
	}
	
	// 给我根节点,我打印出全部信息
	public static void printAllCorpInfo(Corp root) 
	{
		if(root instanceof Leaf)
		{
			root.prinInfo();
		}
		else
		{
			for(Corp sub : ((Branch)root).getSubList())
			{
				printAllCorpInfo(sub);
			}
		}
	}

}

 

4.组合模式的三个角色

  • Component抽象构件角色:定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性,比如我们例子中的name属性,prinInfo()方法就封装在抽象类中
  • Leaf叶子构件:叶子对象,其下再也没有其他的分支,也就是遍历的最小单位
  • Composite树枝构件:树枝对象,它的作用是组合树枝节点和叶子节点形成一个树状结构

5.组合模式的类型

组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?
上面例子中给出的代码叫做安全模式,只在Composite里面声明所有的用来管理子类对象的方法(如下图所示)。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。

另一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化(如下图所示)。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。
 《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。
 参考一下Java中File类型的实现,它同时包含了文件和文件夹的操作方法,可以看出是一种透明类型的组合模式。

 

6.组合模式的优点

  • 高层模块调用简单:一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
  • 节点自由增加:想要增加一个节点,只需要找到它的父节点就行了,非常方便。

7.组合模式的缺点

组合模式有一个非常明显的缺点,看到我们场景类中,树枝和树叶直接使用了实现类。这在面向接口编程上是很不恰当的,与依赖倒置原则冲突。

 

8.组合模式的注意事项

只要是树形结构就要考虑使用组合模式,只要是要体现局部和整体的关系的时候,而且这种关系还比较深,考虑一下组合模式吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是组合模式、装饰器模式、外观模式、享元模式和代理模式的应用案例和代码实现步骤的简要说明: 1. 组合模式 (Composite Pattern): 应用案例:文件系统的目录结构可以使用组合模式来表示,其中目录和文件都可以作为容器或叶子节点,可以方便地进行递归操作。 代码实现步骤:创建一个抽象类或接口表示组件,其中包含添加、删除和获取子组件的方法。实现类分别表示叶子节点和容器节点,容器节点可以包含其他组件。 2. 装饰器模式 (Decorator Pattern): 应用案例:在一个图形绘制软件中,可以使用装饰器模式来实现不同的图形对象以及对图形进行装饰,例如添加颜色、添加边框等。 代码实现步骤:创建一个抽象类或接口表示基本对象或装饰器,其中包含一个基本对象的引用。具体装饰器类继承自该抽象类,并在调用方法时添加额外的功能。 3. 外观模式 (Facade Pattern): 应用案例:在一个电子商务平台中,可以使用外观模式来创建一个统一的接口,将不同子系统的功能封装起来,便于客户端调用。 代码实现步骤:创建一个外观类,该类提供了一个简单的接口来调用多个子系统的功能,并在内部进行协调和管理。 4. 享元模式 (Flyweight Pattern): 应用案例:在一个游戏中,可以使用享元模式来共享不同的游戏资源对象,例如共享相同的纹理、音频等,以减少内存的使用。 代码实现步骤:创建一个享元工厂类来管理共享对象,通过池化技术来缓存和重用对象,并提供一个获取共享对象的方法。 5. 代理模式 (Proxy Pattern): 应用案例:在一个网络请求中,可以使用代理模式来代表真实的网络请求对象,以进行一些额外的操作,例如鉴权、缓存等。 代码实现步骤:创建一个接口或抽象类来表示真实对象和代理对象,代理对象持有一个真实对象的引用,并在调用方法时进行一些额外的处理。 以上是这些设计模式的简要应用案例和代码实现步骤。在实际开发中,可以根据具体需求选择合适的设计模式,并根据设计模式的原则进行设计和实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值