小话设计模式(九)组合模式

组合模式用于构建对象树形结构,实现部分-整体层次,使单个对象和组合对象的使用具有一致性。在iOS的UIView、Cocos2d-x的Node和Unity3d的Transform中广泛应用。以机甲游戏为例,设计了抽象类RobotComponent作为组件基类,包含子组件列表,并定义了不能添加子组件的LeafRobotComponent和不能作为子组件的RootRobotComponent。通过组合模式,可以方便地添加新组件,简化用户代码,但也存在难以限制组件类型的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

组合模式,听名字你可能比较陌生,但是你很可能是这种模式的用户,它的应用非常广泛,例如IOS里的UIView、Cocos2d-x里的Node以及Unity3d里的Transform都是典型的组合模式。

本文简单举个例子,假设我们要开发一款机甲类的游戏,机甲由身体、手臂、腿等组件组成,这些部件还可以搭载火箭助推器和激光加农炮等组件,那么我们就可以考虑使用组合模式来设计。

首先定义一个机器组件的抽象类:

public abstract class RobotComponent
{
	protected RobotComponent _parent = null;
	public virtual RobotComponent parent{ 
		get 
		{ 
			return _parent;
		} 
		set
		{ 
			if (_parent == value) {
				return;
			}
			if (_parent != null) 
			{
				_parent.RemoveComponentFromList (this);
			}
			_parent = value;
			if (_parent != null) 
			{
				_parent.AddComponentToList (this);
			}
		}
	}
	public virtual void RemoveFromParent ()
	{
		parent = null;
	}
	protected List<RobotComponent> _children = new List<RobotComponent> ();
	protected virtual void AddComponentToList(RobotComponent component)
	{
		if (!CanAddComponent (component)) {
			return;
		}
		if (!_children.Contains (component)) {
			_children.Add (component);
		}
	}
	public virtual RobotComponent AddComponent(RobotComponent component)
	{
		component.parent = this;
		return component;
	}
	public RobotComponent AddComponent<T> () where T : RobotComponent, new()
	{
		RobotComponent component = new T ();
		return AddComponent (component);
	}
	protected virtual void RemoveComponentFromList (RobotComponent component)
	{
		if (!_children.Contains (component)) {
			return;
		}
		_children.Remove (component);
		component._parent = null;
	}

	protected virtual bool CanAddComponent(RobotComponent component)
	{
		return true;
	}
}

这个抽象类维护了一个RobotComponent类型的List,用来存放子组件,对外开放了AddComponent和RemoveFromParent方法以及Parent属性。

接着我们可能会考虑到某种类型的组件不能为它添加子组件,例如火箭助推器和激光加农炮,所以我们又定义了一个抽象类——LeafRobotComponent。

public abstract class LeafRobotComponent : RobotComponent
{	
	public override RobotComponent AddComponent(RobotComponent component)
	{
		Console.WriteLine ("LeafRobotComponent cannot add component!");
		return null;
	}
	protected override void RemoveComponentFromList (RobotComponent component)
	{
		Console.WriteLine ("LeafRobotComponent cannot add component! So removing component make no sense!");
	}
}


还有,机器人的身体应该不能被添加到其他组件上,所以需要再定义一个抽象类——RootRobotComponent。

public abstract class RootRobotComponent : RobotComponent
{	
	public override RobotComponent parent{ 
		get 
		{ 
			return null;
		} 
		set
		{ 
			Console.WriteLine ("RootRobotComponent cannot has a parent!");
			_parent = null;
		}
	}
}

这样我们就完成了一个包含根和叶的组合体系了。

然而还没有具体的功能,我们为RobotComponent添加一些属性,并修改CanAddComponent方法。

public abstract class RobotComponent
{
	protected RobotComponent _parent = null;
	public virtual RobotComponent parent{ 
		get 
		{ 
			return _parent;
		} 
		set
		{ 
			if (_parent == value) {
				return;
			}
			if (_parent != null) 
			{
				_parent.RemoveComponentFromList (this);
			}
			_parent = value;
			if (_parent != null) 
			{
				_parent.AddComponentToList (this);
			}
		}
	}
	public virtual void RemoveFromParent ()
	{
		parent = null;
	}
	protected List<RobotComponent> _children = new List<RobotComponent> ();
	protected virtual void AddComponentToList(RobotComponent component)
	{
		if (!CanAddComponent (component)) {
			return;
		}
		if (!_children.Contains (component)) {
			_children.Add (component);
		}
	}
	public virtual RobotComponent AddComponent(RobotComponent component)
	{
		component.parent = this;
		return component;
	}
	public RobotComponent AddComponent<T> () where T : RobotComponent, new()
	{
		RobotComponent component = new T ();
		return AddComponent (component);
	}
	protected virtual void RemoveComponentFromList (RobotComponent component)
	{
		if (!_children.Contains (component)) {
			return;
		}
		_children.Remove (component);
		component._parent = null;
	}

	protected virtual bool CanAddComponent(RobotComponent component)
	{
		if (RemainingTech <= component.TechCost) {
			Console.WriteLine ("We do not have enough technology");
			return false;
		}
		return true;
	}

	protected int _attack = 0;
	public virtual int Attack
	{
		get {
			int ret = _attack;
			foreach (var comp in _children) {
				ret += comp.Attack;
			}
			return ret;
		}
	}

	protected int _speed = 0;
	public virtual int Speed
	{
		get {
			int ret = _speed;
			foreach (var comp in _children) {
				ret += comp.Speed;
			}
			return ret;
		}
	}

	protected int _techCost = 0;
	public virtual int TechCost
	{
		get {
			int ret = _techCost;
			foreach (var comp in _children) {
				ret += comp.TechCost;
			}
			return ret;
		}
	}

	protected int _maxTech = 0;
	public virtual int RemainingTech
	{
		get {
			int ret = _maxTech;
			foreach (var comp in _children) {
				ret -= comp.TechCost;
				if (ret < 0) {
					ret = 0;
					break;
				}
			}
			if (_parent != null && ret > _parent.RemainingTech) {
				ret = _parent.RemainingTech;
			}
			return ret;
		}
	}
}

然后我们定义继承自RootRobotComponent的RobotBody:

public class RobotBody:RootRobotComponent
{
	public RobotBody()
	{
		_maxTech = 100;
	}
}

继承自RobotComponent的RobotArm和RobotLeg:

public class RobotArm : RobotComponent
{
	public RobotArm()
	{
		_attack = 10;
		_techCost = 20;
		_maxTech = 10;
	}
}

public class RobotLeg : RobotComponent
{
	public RobotLeg()
	{
		_attack = 5;
		_speed = 5;
		_techCost = 20;
		_maxTech = 10;
	}
}
以及继承自LeafRobotComponent的RocketBooster和LaserCannon:

public class RocketBooster : LeafRobotComponent
{
	public RocketBooster()
	{
		_techCost = 3;
	}
	public override int Speed
	{
		get {
			return 2;
		}
	}
}

public class LaserCannon : LeafRobotComponent
{
	public LaserCannon()
	{
		_techCost = 3;
	}
	public override int Speed
	{
		get {
			return -1;
		}
	}
	public override int Attack
	{
		get {
			return 3;
		}
	}
}

然后我们就可以组装机甲了:

		RobotComponent robot = new RobotBody ();
		RobotComponent arm1 = new RobotArm ();//robot.AddComponent<RobotArm> ();
		RobotComponent arm2 = robot.AddComponent<RobotArm> ();
		RobotComponent leg1 = new RobotLeg ();//robot.AddComponent<RobotLeg> ();
		RobotComponent leg2 = robot.AddComponent<RobotLeg> ();
		arm1.AddComponent<LaserCannon> ();
		arm2.AddComponent<LaserCannon> ();
		leg1.AddComponent<RocketBooster> ();
		leg2.AddComponent<RocketBooster> ();
		robot.AddComponent<RocketBooster> ();
		robot.AddComponent<RocketBooster> ();
		robot.AddComponent (arm1);
		robot.AddComponent (leg1);
		robot.AddComponent<LaserCannon> ();

		Console.WriteLine (robot.RemainingTech);
		Console.WriteLine (robot.Speed);
		Console.WriteLine (robot.Attack);

输出:

We do not have enough technology

2

16

36


组合模式的优点:

1、定义了组合对象的层次结构,可以不断的递归产生各种复杂的组件。

2、简化了用户的代码,用户可以一致地使用组合组件和单个组件。

3、易于增加新类型的组件,新组件添加后可以和原来的组件一起使用。

缺点:

很难限制组合中的组件:有时候你可能希望一个组合只能包含某些特定的组件,就只能在运行时进行检查。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值