以下情况使用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_Hcpp代码部分:
#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添加功能,这些功能可以再动态的撤销。可读性和可维护都有很大的提高。