前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我用过的设计模式(8)-- 装饰者模式

我用过的设计模式(8)-- 装饰者模式

原创
作者头像
看、未来
修改2021-03-01 14:41:47
2960
修改2021-03-01 14:41:47
举报
文章被收录于专栏:CSDN搜“看,未来”
在这里插入图片描述
在这里插入图片描述

装饰者模式

动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更加灵活。

我一直没整明白这个模式到底是怎么玩的,是弄一个虚基类,然后去拓展它的很多子类吗?我以前一直是这么认为的。

我现在依旧认为这是其中的一部分,但是后来,我又有了新的认知。

新的认知来源于我去学Python的那段时间,我开了三个Python基础入门的班,在备课的过程中,接触到了Python的装饰器。

当我看到这个名字的时候,第一反应就是装饰器模式,这,映射到C++当中,是不是就是装饰者模式呢?

我看了下去,因为我之前理解的装饰者模式是基于虚基类的,而Python可不跟你玩这个。

看了Python的装饰器,我不由自主的想到了C++的函数指针,不就是这个道理吗?搞得那么复杂,函数指针还更加的灵活多变,于是我果断选择了跟大家讲函数指针的内容。

关于函数指针和装饰器的部分可以看我的“偷偷学Python”系列最后一天:我要偷偷的学Python,然后惊呆所有人(最后一天)


函数指针方面的代码我就不展示啦,平时都在用着,我就展示一下虚基类在装饰者模式中的应用吧。

==又是线程池==,感觉这个线程池已经客串了我好多个设计模式了。不过每次的着力点都不一样,这次,是Task类。


实例:又是线程池

代码语言:txt
复制
//pthreadpool.h

#pragma once

#include <pthread.h>
#include <unistd.h>
#include <list>	//据说list不安全,不安全就不安全吧,更不安全的都忍了
#include "Cond.h"	//封装过的条件变量类,继承自封装的mutex锁类,所以具有锁和条件变量的双重属性

using namespace std;

这里不打注释,这次的主角是它
class Task	//任务接口,每个任务必须实现的接口,以供工作线程调度任务的执行
{
public:
    Task() {}
    virtual ~Task() {}
    virtual int run() = 0; //留给子类实现
};

typedef list<Task*> list_task; //任务队列,用于暂存等待处理的任务,等待线程唤醒时处理,提供一种缓冲机制。

class Pthread_Pool	//线程池类
{
public:
    Pthread_Pool(unsigned int max = 100, unsigned int min = 10, unsigned int wait = 60);
    ~Pthread_Pool();
    void addTask(Task* task);	// 往任务队列中添加新线程
    看这里看这里

private:
    static void* taskThread(void* arg);// 工作线程
    void createThread();		// 新建一个线程
    void destroyThread();		// 销毁一个线程池

    unsigned int maxcount;		// 最大线程数
    unsigned int mincount; 		// 最小线程数
    unsigned int count;	 		// 当前线程池中线程数
    unsigned int waitcount; 	// 等待线程数
    unsigned int waitsec;		// 等待时间
    list_task	 taskList;      //任务队列
    Cond taskCond;    //任务锁,线程接任务时使用
    Cond cond;        //线程锁,创建线程时使用
    bool Stop;                  //线程池是否被允许运作,初始化线程池对象时置0,线程池销毁时置为1
};

具体代码太长,只需要知道工作线程会去run就可以。

调用的地方是这样的:

代码语言:txt
复制
class DoTask : public Task
{
public:
    DoTask(BtoC& send, PacketCommand1& packet);

    int run();
private:
    DB_command* task_db;
    BtoC* m_send;
    PacketCommand1 m_packet;
    PacketCommand3* f_packet;
};


class BackServer
{
public:
    BackServer(char* IPnum);
    ~BackServer() {}
    int run();
private:
    PacketCommand1 m_packet;
    BtoC m_send;
    Pthread_Pool* m_pool;
};
代码语言:txt
复制
int BackServer::run()
{
    int n = 0;
    while (1)
    {
        n = m_send.Read_date(m_packet.getData());
        m_packet.setSize(n);
        DoTask* t = new DoTask(m_send, m_packet);
        m_pool->addTask(t);
    }
    return 0;
}

如果要看完整源码的话,可以移步:

【C++】勉强能看的线程池详解

这篇详尽的介绍了我的线程池实现过程,但是没有放调用部分,调用部分就是上面这两段。

我用过的设计模式(7)-- 享元模式

这篇放了源码和调用部分,加上了一个对象池的实现,是讲池技术的。


回到装饰者模式

装饰者模式的

装饰类和被装饰类可以独立发展,不会互相耦合。

换句话说,被装饰类也不用知道装饰类,装饰类是从外部来拓展被装饰类的功能,而装饰类也不用知道自己要去装饰谁。

装饰模式是继承关系的一个替代方案,从上面可以看出来,不管装饰多少层,它还是最原始的那个东西。

装饰模式可以动态的拓展一个实现类的功能,无需多言。

缺点

多层的装饰是比较复杂的,一出现问题,你很难知道是哪一层装饰出问题。

所以尽量减少装饰的数量,降低系统复杂度。

使用场景

代码语言:txt
复制
需要动态拓展一个类的功能,或者给一个类添加附加功能。
需要动态的给一个对象增加功能,这些功能可以动态的撤销。
需要为一批的兄弟类进行改装或加装功能,当然是首选装饰者模式。

装饰者模式是对继承的有力补充。


原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装饰者模式
  • 实例:又是线程池
  • 回到装饰者模式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档