Cocos2d-x中应用装饰者模式

装饰者模式(Decorator Pattern)
以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

上边是装饰者模式的应用,今天在做coco2d项目的时候使用了装饰者模式创建场景,觉得大多数的场景创建都适用这种模式。就拿菜单场景来举例,下面看代码

装饰模式头文件的代码:

主要实现了装饰模式需要的各种类。

#ifndef _MENULAYER_H
#define _MENULAYER_H
#pragma once
#include <iostream>
#include "cocos2d.h"
#include "PlayGame.h"
USING_NS_CC;
//抽象的被装饰类
class CComponet
{
public:
	virtual void Operation(Layer* pLayer) = 0;
};
//具体的被装饰类
class CConcreteComponet :public CComponet
{
public:
	void Operation(Layer* pLayer){};
};
//抽象的装饰类
class CDecorator :public CComponet
{
public:
	CComponet* p;
	void setComponet(CComponet* that);
	void Operation(Layer* pLayer);
};
//具体的装饰类菜单
class CConcreteDecoratorMenu :public CDecorator
{
public:
	void Operation(Layer* pLayer);
};
//具体的装饰类背景
class CConcreteDecoratorBackGroud :public CDecorator
{
public:
	void Operation(Layer* pLayer);
};
#endif//_MENULAYER_H
cpp代码部分:

代码实现部分,两个装饰子类,一个菜单,一个背景。

#include "MenuLayer.h"
void CDecorator:: setComponet(CComponet* that)
{
	p = that;
}
void CDecorator:: Operation(Layer* pLayer)
{
	if (p != NULL)
	{
		p->Operation(pLayer);
	}
}

void CConcreteDecoratorMenu:: Operation(Layer* pLayer)
{

	//调用父类中的接口
	CDecorator::Operation(pLayer);
	//添加自己的装饰
	auto winSize = Director::getInstance()->getWinSize();
	auto startItem = MenuItemImage::create(
		"start_1.png","start_2.png",CC_CALLBACK_1(PlayGame::menuStartCallback,(PlayGame*)pLayer));
	//startItem->setPosition(Point(winSize.width / 2,winSize.height / 2));
	startItem->setPosition(Point::ZERO);
	startItem->setAnchorPoint(Point(0,0));

	auto menu = Menu::create(startItem,NULL);
	menu->setPosition(Point::ZERO);
	pLayer->addChild(menu,1);
}

void CConcreteDecoratorBackGroud:: Operation(Layer* pLayer)
{
	PlayGame* pPlayGameLayer = (PlayGame*)pLayer;
	//调用父类中的接口
	CDecorator::Operation(pLayer);
	//添加自己的装饰
	auto winSize = Director::getInstance()->getWinSize();
	Sprite* pSprite = Sprite::create("playbg.png");
	pPlayGameLayer->m_Sprite = pSprite;
	pSprite->setPosition(Point(pSprite->getContentSize().width/2,pSprite->getContentSize().height / 2));
	pLayer->addChild(pSprite,-1);
}
场景类init函数部分代码:

在init中装饰了一个菜单

bool PlayGame:: init()
{
	if (!Layer::init())
	{
		return false;
	}
	//创建一个被装饰者对象
	CConcreteComponet Aa;
	//创建具体的装饰对象
	CConcreteDecoratorMenu aA;//添加菜单装饰
	//装饰是有序的,a->aA;
	aA.setComponet(&Aa);
	//最终aA执行的是二者结合的结果。
	aA.Operation(this);
}
菜单的calback函数代码:

按钮的回调函数中又给场景装饰了一个背景。

void PlayGame::menuStartCallback(cocos2d::Ref* pSender)
{
	//创建一个被装饰者对象
	CConcreteComponet Aa;
	CConcreteDecoratorBackGroud aB;//添加背景装饰
	aB.setComponet(&Aa);
	aB.Operation(this);
	//this->m_Sprite->setPosition(Point(50,50));
}
这样把init中的把不同的功能的代码都移到了每个装饰子类中实现,降低耦合性。可以动态的给一个layer添加功能,这些功能可以再动态的撤销。可读性和可维护都有很大的提高。

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...