装饰模式:
动态地给一个对象添加一些额外的职责,就扩展功能而言,该模式比生成子类方式更为灵活。
如果我按照继承树的方式来处理,那我生成一个实体【石榴树】,类与类之间的结构会帮我把所有内容处理好。但我如果要更改其中一个步骤,比如创造一种石榴树,保留其他特性,但不能存在!(好吧,非常抽象,大概理解为,这个石榴树是非存在物,是一种灵体),那我就要重新做一个这样的区别。
如果我用装饰器的方法,我可以一层一层去包裹这个石榴树,最后建成它。比如【石榴树!【树【植物【生物【物体【存在】】】】】】
这两个之间有什么区别吗?继承树中的问题可以用建造者模式来消除嘛?
我决定试一下用装饰器来处理这个石榴树的情况。这似乎意味着,任何一个半吊子,比如【物体【存在】】,也可以作为实体存在了。这就是与建造者模式的差异之一。但也只是方便与否的关系。
不,不仅仅是方便与否的关系,因为如果作为实体存在,就最好能够满足一些功能……
因为考虑到实际需求,我们的石榴树向前会变成*【预支付的】石榴树*,向后会变成*石榴树【植物】……但是前缀就是石榴树会遇到的情况,后缀就是石榴树当前的某种属性状态?
这样只涉及石榴树的属性?抑或可以用在非属性的任何地方,比如建造中。
先复习一下装饰模式-《设计模式与游戏完美开发》
public abstract class IShape
{
//注意,有一个属性。似乎就是用来作为那个根基的存在(一个product)。
protected RenderEngine m_RenderEngine=null;
//子类则是需要可以获得这个存在。
public void SetRenderEngine(RenderEngine theRenderEngine)
{
m_RenderEngine=theRenderEngine;
}
public abstract void Draw();
public abstract string GetPolygon();
}
//继承这个接口的内容
public class Sphere :IShape
{
public override void Draw()
{
m_RenderEngine.Render("画个球")
}
public override string GetPolygon()
{
return "Sphere多边形"
}
}
在以上内容可以了解到,接口就像是一个共用的工具。当类里面有共用的承诺的时候,由这个父类接口来兑现!
而下面这个子类,就不是一个图形类了。它是为了扩展ishape的功能而存在的。我们看看它要怎么做到这一点。
public abstract class IShapeDecorator :IShape
{
IShape m_Component;
//构造这个类的时候,就需要获得一个组件。这种组件符合ISHAPE的接口。为了满足接口的功能,它支持调用了ISHAPE的内容,那这样是没有任何变化的。
public IShapeDecorator(IShape theComponent)
{
m_Component =theComponent;
}
public override void Draw()
{
m_Component.Draw();
}
public override string GetPolygon()
{
return m_Component.GetPolygon();
}
}
这个子类并不满足ishape的所有方法。它就像是包裹了shape的外面一层。任何其他物体需要通过这个外部的一层获得到内部的东西。
public abstract class IAdditional
{
//神奇,它也有和Ishapey相似的内容。
RenderEngine m_RenderEngine =null;
public void SetRenderEngine(RenderEngine theRenderEngine)
{
m_RenderEngine =theRenderEngine;
}
//这就是有意义的那个功能
public abstract void DrawOnShape(IShape theShape);
}
//第一个真正有用的类,外框,一个功能而已
public class Border :IAdditional
{
public override void DrawOnShape(IShape theShape)
{
m_RenderEngine.Render("draw Border on "+theShape.GetPoly());
}
}
public class BorderDecorator:IShapeDecorator
{
Border m_Border =new Border();
public BorderDecorator(IShape theComponent) :base(theComponent){}
public virtual void SetRenderEngine(RenderEngine theRenderEngine)
{
base.SetRenderEngine(theRenderEngine);
//因为这个画外框的功能也需要这个engine,所以给它
m_Border.SetRenderEngine(theRenderEngine);
}
public override void Draw()
{
base.Draw();
m_Border.DrawOnShape(this);
}
}
//测试
sphere theSphere =new Sphere();
theSphere.SetRenderEngine(theOpenGL);
BorderDecorator =theShereWithBorder =new BorderDecorator(theShere);
theSphereWithBorder.SetRenderEngine(OPGL);
theSphereWithBorder.Draw();
我们看测试里,我们先构建了我们要画的一个组件,它是继承于一个抽象的类别的。
在我自己的需求里,我希望的是这个抽象是product_ab,而我们的一个内容,比如存在,就是继承这个抽象product_ab的product,例如通过如下结果来处理一个树:
Product myproduct =new Product();
myproduct.set_creator(productBuilder);
ExistDecorator existdeco =new ExistDecorator(myproduct);
existdeco.set_creator(existBuilder);
ObjectDecorator objectdeco =new ObjectDecorator(existdeco);
existdeco.set_creator(existBuilder);
LifeDecorator lifedeco =new LifeDecorator(existdeco);
lifedeco.set_creator(LifeBuilder);
PlantDecorator plantdeco =new plantDecorator(lifedeco);
plantdeco.set_creator(plantBuilder);
TreeDecorator treedeco =new treeDecorator(plantdeco);
treedeco.set_creator(treeBuilder);
PometreeDecorator pometreedeco =new PometreeDecorator(treedeco);
pometreedeco.set_creator(PometreeBuilder);
Pometree my_tree= pometreedeco.Create();
这个情况是可行的。现在实现一下。
首先需要规定一个creator的形式。比如它包含什么基础参数,什么公用的函数,比如add。
同时,这些LifeDecorator必须要继承于一个类,
这个父类,需要有一个属性接口,即product。
这个父类,需要有一个creator接口,即set_creator处理的。
好了。搞定!这样直接返回了一个造好的石榴树。而且我们可以调整在制造中的任何细节。同时也似乎比建造者模式要更为灵活?
这样想来,如果我们游戏中的石榴树不会有什么本体上的改变,其实无需实现这样的动态性吧?不过,那个【未来】的【石榴树】中的【未来】,肯定可以作为一个装饰器存在了。
在书本中,作者提醒我们,如果早期规划就知道会有大量的组件来扩展功能的话,那么可以用类似unity中的组件的设计方式。这个设计方式叫做ECS设计模式。
Entity Component System.
这个模式不同于组合模式,因为它只是方便增加各类组件,来实现功能,包括参数,也可以去掉组件。而组合模式会涉及到嵌套。在使用解释器的时候我们再考虑组合模式吧。

本文探讨了装饰模式在游戏开发中的应用,特别是如何利用该模式动态地为对象添加职责,以实现更灵活的对象功能扩展。对比了装饰模式与建造者模式、组合模式的区别,并讨论了在游戏开发中如何选择合适的设计模式。
5127

被折叠的 条评论
为什么被折叠?



