常用设计模式之装饰器模式

装饰器模式

前言

 当系统需要新功能的时候,是向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为,这种做法的问题在于,它们在主类中加入了新的字段,新的方法和逻辑,从而增加了主类的复杂度,并且新加入的东西仅仅是为了满足一些只在特定情况下才会执行的特殊行为的需要,这时候一般会采用装饰器模式。

场景

 试想一个经常在游戏中遇到的场景,给一个人物角色添加装备服饰,从而改变这个角色的外观,甚至增加某项属性值,应该如何实现呢?

如果不使用任何设计模式,最简单的方式可能是这样:

 与之对应的代码是这样的:

#include <stdio.h>
#include <iostream>
#include <string>

using namespace std;

class Person {
    
    
 private:
  string m_name;

 public:
  Person(string name) : m_name(name) {
    
    }
  void wearTShirts() {
    
     printf("wear big Tshirt\n"); }

  void wearBigTrouser() {
    
     printf("wear big trouser\n"); }

  void wearSneakers() {
    
     printf("wear bad sneakers\n"); }

  void wearSuit() {
    
     printf("wear suit\n"); }

  void wearTie() {
    
     printf("wear tie\n"); }

  void wearLeatherShoes() {
    
     printf("wear leatherShoes\n"); }

  void show() {
    
     printf("dress up %s", m_name.c_str()); }

};


int main(int argc, char** argv)
{
    
    
  Person person("xt");
  printf("The first dress:\n");
  person.wearBigTrouser();
  person.wearLeatherShoes();
  person.wearSneakers();
  person.show();
  printf("The first dress:\n");
  person.wearSuit();
  person.wearTie();
  person.wearTShirts();
  person.show();
  return 0;
}

 不采用任何设计模式,也可以实现这个功能,但是如果我们想再给person添加一个超人装扮,那么就需要手动改这个类的内容,虽然可以达成目的,但是违背了开放-封闭原则,并不是一个合理的行为。

装饰器模式

 为角色穿衣服,我们想达到的目的就是按照指定的顺序把功能给串联起来,想要达到这个目的,就可以考虑使用装饰器模式了。

 来看一下装饰器模式的原理及结构:

本文图片来源于程杰《大话设计模式》,需要的同学可以关注公众号程序员DeRozan,回复1207领取。

《C++ Primer》《Effective C++》是C++开发者必不可少的书籍,如果你想入门C++,以及想要精进C++开发技术,这两本书可以说必须要有。此外,《Linux高性能服务器编程》以及《Linux多线程服务端编程:使用muduo C++网络库》.(陈硕)》是快速提高你的linux开发能力的秘籍。《大话设计模式》可以增强我们的模型提取及设计能力,写出更优雅的代码。在网上搜索相关资源也要花费一些力气,需要的同学可以关注公众号【程序员DeRozan】,回复【1207】快速免费领取~

 图中,Component是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteCommponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator是一个装饰抽象类,继承Component,从外类类扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。根据上面的场景,我们可以这样完成设计:

//对象抽象类,包含一个需要完成的动作。
class Person {
    
    
 public:
  virtual void wearClothes() = 0;
};

//具体对象,重写动作接口
class realPerson : public Person {
    
    
 public:
  void wearClothes() override {
    
     printf("wear nothing\n"); }
};

//装饰器抽象类,继承对象抽象类,内含两个方法,一个是获得一个已经装饰好的对象,一个是调用这个对象的方法
class FineryDecorator : public Person {
    
    
 public:
  void SetBase(Person* person) {
    
     m_person = person; }

  void wearClothes() override {
    
     m_person->wearClothes(); }

  Person* m_person;
};


//具体的装饰类
class TShirt : public FineryDecorator {
    
    
 public:
  void wearClothes() override {
    
    
    m_person->wearClothes();
    printf("wear TShirt\n");
  }
};

class Trouser : public FineryDecorator {
    
    
 public:
  void wearClothes() override {
    
    
    m_person->wearClothes();
    printf("wear Trouser\n");
  }
};

class Suit : public FineryDecorator {
    
    
 public:
  void wearClothes() override {
    
    
    m_person->wearClothes();
    printf("wear Suit\n");
  }
};

void test2() {
    
    
  realPerson* realp = new realPerson();
  TShirt* th = new TShirt();
  Trouser* tr = new Trouser();
  Suit* su = new Suit();

  th->SetBase(realp);
  tr->SetBase(th);
  su->SetBase(tr);
  su->wearClothes();
}

int main(int argc, char** argv) {
    
     test2(); }

 程序输出:

sh-4.4$ ../build/linux/x86_64/release/DecoratorMode 
wear nothing
wear TShirt
wear Trouser
wear Suit

 可以分析出,装饰器模式中重要的步骤是SetBase以及wearClothes这个方法,SetBase可以每次都更新自己的父类FineryDecorator所持有的m_person对象,以至于父类FineryDecorator中wearClothes方法每次都是最新对象m_person中的wearClothes 方法,然后在这个方法后面再添加其他的自定义方法。

 总结一下装饰器模式

猜你喜欢

转载自blog.csdn.net/dddgggd/article/details/129721768