【学习笔记】C/C++ 设计模式 - 工厂模式(上)
阅读原文时间:2023年07月08日阅读:1

介绍说明

在年初七的时候,学习了工厂模式,今天在复习的时候发现漏了几个知识点,因此重写这篇文章,以循环渐进的描述方式来对比不同的使用技巧。

工厂设计模式属于 “创建型设计模式”,在我理解,就是为一个相同类型的功能模块抽象出一组接口定义,统一采用各种方案实现的相同类型的功能模块。主要的业务逻辑不必关心该功能模块采用什么方案实现,只需关心如何使用抽象出来的接口即可。完美体现出这句名言:计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决.

在我看来,工厂设计模式其核心是标准接口的定义,其次才是体现在对象创建技巧上,应该改为接口设计模式来命名会更加贴切些,不明白为什么会以工厂来命名。可能是工厂生产都是标准化生产,所以这么命名?也可能是由于我刚开始正式涉及应用开发领域,编写和阅读代码量不够,还有其它的场景我未曾经历过,缺乏一些认知导致。若你有不同的见解,请留言说一下,感谢感谢。

某个功能模块,有多种实现方案,需要同时兼容这些方案,在不同的场景中需要切换或同时使用的时候。

例如前段时间比较火的智能语音音箱产品,都是以语音识别技术为基础,配合 TTS、NLP 等技术实现。语音识别技术有科大讯飞、奇梦者、声智等企业提供方案。开发以语音识别技术为基础的产品,为了持续提升产品的用户体验,可能都会遇到同时兼容多家方案的情况,那么就可以抽象出一套不依赖具体方案,只体现出具体功能的接口,基于这些接口来封装各家方案的SDK,主要业务逻辑仅使用抽象出来的接口。通过售后部门、测试部门联合确认当前正式版本使用的效果,以及其它各家的效果,来确认下一版本采用哪家方案,这时候只需要修改一个参数或某个配置文件即可完成切换,而不会影响业务逻辑的实现。

其它例子:

  • 日志输出(可以通过串口输出、也可以通过USB输出、也可以通过网络传输到云端服务器又或者写入文件)
  • 数据通信(可以通过 websocket 实现、也可以通过 http、https、socket实现、也可以是 local socket)
  • 数据存储(ini配置文件、数据库、二进制文件等)

核心思想就是增加一个中间层接口,不同的实现方案都去实现这些接口,而业务逻辑则去调用这些接口。在 C++ 中,利用的继承和纯虚函数实现,在 C 中,可以通过函数指针实现。

  • 直接调用方式
  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式(另外写一篇文章介绍)

这里以音频播放器来作为一个例子,为了方便不同具体播放器之间的切换,首先抽象出音频播放器中常用的接口,然后在播放器的具体实现中,采用了 “调用外部命令” 以及 “使用mplayer接口” 两种方式实现播放器(没有提供具体实现,仅为了便于理解工厂设计模式)。

调用外部播放器命令实现,可以通过进程控制技术来实现。示例中之所以增加 init() 和 release() 接口定义,一来是为初始化播放器提供合适的调用机会,二来也是提供了调整某个播放器参数来灵活使用,例如指定外部播放器。

首先抽象播放器的常用接口,如初始化、播放、暂停、恢复、重播、停止、释放、设置事件监听回调以及相应事件回调接口。这些接口只定义不作具体实现,由后续具体播放器去继承实现,即定义了一组标准接口,由具体的播放器遵循这些标准接口而设计。

/**
******************************************************************************
* @文件        AudioPlayerInterface.h
* @版本        V1.0.0
* @日期
* @概要        工厂模式示例代码-播放器接口定义
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#ifndef __AUDIO_PLAYER_INTERFACE_H
#define __AUDIO_PLAYER_INTERFACE_H

#define AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS                            0
#define AUDIO_PLAYER_INTERFACE_RETURN_INVALID_PARAMETER                 -1
#define AUDIO_PLAYER_INTERFACE_RETURN_FAIL                              -2

// 事件监听器
class AudioPlayerEventMonitor
{
public:

    typedef enum
    {
        PLAYER_EVENT_TYEP_PLAY,                     // 开始播放
        PLAYER_EVENT_TYEP_PAUSE,                    // 暂停播放
        PLAYER_EVENT_TYEP_RESUME,                   // 恢复播放
        PLAYER_EVENT_TYEP_STOP,                     // 停止播放
        PLAYER_EVENT_TYEP_DONE,                     // 播放完成
    }PLAYER_EVENT_TYEP_E;

    typedef struct
    {
        PLAYER_EVENT_TYEP_E event;                  // 事件类型
    }TAudioPlayerEvent;

public:
    virtual void onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent) = 0;
};

// 抽象结构类:
// 1. 所有播放器都需要继承该来实现里面的所有接口
// 2. 主业务逻辑通过调用这里的接口, 即可控制播放器
class AudioPlayer
{

public:

    AudioPlayer() { }

    // 划重点, 如果该析构函数未以 virtual 声明, 那么在 new 子类对象转换为父类指针后再 delete, 子类的析构函数不会被调用
    virtual ~AudioPlayer() { }                                  

    // 设置事件监听
    virtual int setEventMonitor(AudioPlayerEventMonitor *pMonitor) = 0;

    virtual int  init(void *pargs)                   = 0;       // 初始化
    virtual int  release()                           = 0;       // 释放

    virtual int  play(const char *pAudioFile)        = 0;       // 播放指定音频文件或网络音频
    virtual int  reset()                             = 0;       // 重新播放上一次指定的音频
    virtual bool isPlaying()                         = 0;       // 判断是否正在播放
    virtual int  pause()                             = 0;       // 暂停播放
    virtual int  resume()                            = 0;       // 恢复播放
    virtual int  stop()                              = 0;       // 停止播放

    virtual int  setVolume(int volume)               = 0;       // 设置音量
    virtual int  getVolume()                         = 0;       // 获取音量
};

#endif

以下为通过调用外部命令实现的具体播放器,继承上述接口(AudioPlayerInterface)来提供具体的实现。

/**
******************************************************************************
* @文件        AudioPlayerExternal.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 通过调用外部命令实现播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#ifndef __AUDIO_PLAYER_EXTERNAL_H
#define __AUDIO_PLAYER_EXTERNAL_H

#include <iostream>
#include <string>
#include "../AudioPlayerInterface.h"

using namespace std;

// 继承音频播放器接口并实现
class AudioPlayerExternal : public AudioPlayer
{
private:

    string                        mExternalCommand;
    string                        mPlayerFile;

    AudioPlayerEventMonitor       *mpAPEventMonitor = NULL;

public:

    AudioPlayerExternal() { printf("AudioPlayerExternal()\n"); }
    ~AudioPlayerExternal() { printf("~AudioPlayerExternal()\n"); }

    // 设置事件监听
    virtual int setEventMonitor(AudioPlayerEventMonitor* pAPEventMonitor) { mpAPEventMonitor = pAPEventMonitor; return 0; };

    virtual int init(void *pExternalCommand) override;            // 初始化
    virtual int release() override;                               // 释放

    virtual int play(const char* pAudioFile) override;            // 播放指定音频文件或网络音频
    virtual int reset() override;                                 // 重新播放上一次指定的音频
    virtual bool isPlaying() override;                            // 判断是否在播放
    virtual int pause() override;                                 // 暂停播放
    virtual int resume() override;                                // 恢复播放
    virtual int stop() override;                                  // 停止播放

    virtual int setVolume(int volume) override;                   // 设置音量
    virtual int getVolume() override;                             // 获取音量
};

#endif

/**
******************************************************************************
* @文件        AudioPlayerExternal.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 通过调用外部命令实现播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include <iostream>
#include "AudioPlayerExternal.h"

int AudioPlayerExternal::init(void *pExternalCommand)
{
    printf("AudioPlayerExternal: init()...\n");

    // 如果没有指定播放器, 那么默认为 tinyplayer
    if(NULL == pExternalCommand)
        pExternalCommand = (void*)"tinyplayer";

    mExternalCommand = (char *)pExternalCommand;
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::release()
{
    printf("AudioPlayerExternal: release()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::play(const char* pAudioFile)
{
    printf("AudioPlayerExternal: play()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::reset()
{
    printf("AudioPlayerExternal: reset()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

bool AudioPlayerExternal::isPlaying()
{
    printf("AudioPlayerExternal: isPlaying()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::pause()
{
    printf("AudioPlayerExternal: pause()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::resume()
{
    printf("AudioPlayerExternal: resume()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::stop()
{
    printf("AudioPlayerExternal: stop()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::setVolume(int volume)
{
    printf("AudioPlayerExternal: setVolume() volume:%d ...\n", volume);
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerExternal::getVolume()
{
    printf("AudioPlayerExternal: getVolume() ...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

以下为通过调用 mplayer 实现的具体播放器,也是通过继承接口(AudioPlayerInterface)来提供具体的实现。

/**
******************************************************************************
* @文件        AudioPlayerMPlayer.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 通过 MPlayer 实现播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#ifndef __AUDIO_PLAYER_MPLAYER_H
#define __AUDIO_PLAYER_MPLAYER_H

#include <iostream>
#include <string>
#include "../AudioPlayerInterface.h"

using namespace std;

// 继承音频播放器接口并实现
class AudioPlayerMPlayer : public AudioPlayer
{
private:

    string                            mPlayerFile;
    AudioPlayerEventMonitor           *mpAPEventMonitor = NULL;

public:

    AudioPlayerMPlayer() { printf("AudioPlayerMPlayer()\n"); }
    ~AudioPlayerMPlayer() { printf("~AudioPlayerMPlayer()\n"); }

    // 设置事件监听
    virtual int setEventMonitor(AudioPlayerEventMonitor* pAPEventMonitor) { mpAPEventMonitor = pAPEventMonitor; return 0; };

    virtual int init(void* pExternalCommand) override;            // 初始化
    virtual int release() override;                               // 释放

    virtual int play(const char* pAudioFile) override;            // 播放指定音频文件或网络音频
    virtual int reset() override;                                 // 重新播放上一次指定的音频
    virtual bool isPlaying() override;                            // 判断是否在播放
    virtual int pause() override;                                 // 暂停播放
    virtual int resume() override;                                // 恢复播放
    virtual int stop() override;                                  // 停止播放

    virtual int setVolume(int volume) override;                   // 设置音量
    virtual int getVolume() override;                             // 获取音量
};

#endif

/**
******************************************************************************
* @文件        AudioPlayerMPlayer.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 通过 MPlayer 实现播放器(这里仅用于理解工厂设计模式)
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include <iostream>
#include "AudioPlayerMPlayer.h"

int AudioPlayerMPlayer::init(void* pMPlayerCommand)
{
    printf("AudioPlayerMPlayer: init()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::release()
{
    printf("AudioPlayerMPlayer: release()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::play(const char* pAudioFile)
{
    printf("AudioPlayerMPlayer: play()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::reset()
{
    printf("AudioPlayerMPlayer: reset()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

bool AudioPlayerMPlayer::isPlaying()
{
    printf("AudioPlayerMPlayer: isPlaying()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::pause()
{
    printf("AudioPlayerMPlayer: pause()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::resume()
{
    printf("AudioPlayerMPlayer: resume()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::stop()
{
    printf("AudioPlayerMPlayer: stop()...\n");
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::setVolume(int volume)
{
    printf("AudioPlayerMPlayer: setVolume() volume:%d ...\n", volume);
    return AUDIO_PLAYER_INTERFACE_RETURN_SUCCESS;
}

int AudioPlayerMPlayer::getVolume()
{
    printf("AudioPlayerMPlayer: getVolume() ...\n");
    return 0;
}

单元测试代码:具体关注 interfaceTest()

/**
******************************************************************************
* @文件        test_AudioPlayer.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式单元测试
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "AudioPlayerInterface.h"

// 纯接口测试需要用到
#include "player/AudioPlayerMPlayer.h"
#include "player/AudioPlayerExternal.h"

class TestAudioPlayer : public AudioPlayerEventMonitor
{
private:

        // 通过 AudioPlayerEventMonitor 继承
    virtual void onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent) override;
    void audioPlayerOps(AudioPlayer* pAudioPlayer);             // 音频播放器接口测试
    void interfaceTest(void);                           // 纯接口测试

public:

    void test(void);

};

/**
******************************************************************************
* @文件        test_AudioPlayer.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式单元测试
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#include <iostream>
#include "test_AudioPlayer.h"

// 播放器事件状态回调通知
void TestAudioPlayer::onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent)
{

}

// 音频播放器操作
void TestAudioPlayer::audioPlayerOps(AudioPlayer* pAudioPlayer)
{
    pAudioPlayer->setEventMonitor(this);
    pAudioPlayer->init(NULL);
    pAudioPlayer->setVolume(15);
    pAudioPlayer->play("test.mp3");
    pAudioPlayer->reset();
    pAudioPlayer->pause();
    pAudioPlayer->resume();
    pAudioPlayer->stop();
    pAudioPlayer->release();

    return ;
}

// 接口测试(业务逻辑代码中会暴露具体实现)
void TestAudioPlayer::interfaceTest(void)
{
    AudioPlayer* pAudioPlayer = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = new AudioPlayerMPlayer();
    audioPlayerOps(pAudioPlayer);
    delete pAudioPlayer;

    // 测试以调用外部命令的方式实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = new AudioPlayerExternal();
    audioPlayerOps(pAudioPlayer);
    delete pAudioPlayer;

    puts("-----------------------------------------------------------------------");
}

void TestAudioPlayer::test(void)
{
    puts("interface test ...");
    interfaceTest();

    return;
}



interface test ...
-----------------------------------------------------------------------
AudioPlayerMPlayer()
AudioPlayerMPlayer: init()...
AudioPlayerMPlayer: setVolume() volume:15 ...
AudioPlayerMPlayer: play()...
AudioPlayerMPlayer: reset()...
AudioPlayerMPlayer: pause()...
AudioPlayerMPlayer: resume()...
AudioPlayerMPlayer: stop()...
AudioPlayerMPlayer: release()...
~AudioPlayerMPlayer()
-----------------------------------------------------------------------
AudioPlayerExternal()
AudioPlayerExternal: init()...
AudioPlayerExternal: setVolume() volume:15 ...
AudioPlayerExternal: play()...
AudioPlayerExternal: reset()...
AudioPlayerExternal: pause()...
AudioPlayerExternal: resume()...
AudioPlayerExternal: stop()...
AudioPlayerExternal: release()...
~AudioPlayerExternal()
-----------------------------------------------------------------------

通过 TestAudioPlayer 单元测试类可以发现,具体的播放器暴露在业务逻辑上了,违反设计模式六大原则中的 “迪米特法则”(又称最少知道原则),因此需要再封装一层简单的创建、释放接口,来屏蔽具体播放器对象的创建细节,这就是传说中的 “简单工厂模式” 。

定义一个 AudioManager 类,来作为具体播放器类对象的创建和释放。业务逻辑通过 AudioManager 来创建和释放具体的播放器类对象。命名空间 simple 的定义是为了方便后续增加 “工厂方法模式” 示例,与本文介绍的工厂模式无关。

/**
******************************************************************************
* @文件        AudioManager.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#ifndef __AUDIO_MANAGER_H
#define __AUDIO_MANAGER_H

#include "AudioPlayerInterface.h"

namespace simple {

class AudioManager
{
public:

    typedef enum {
        AUDIO_PLAYER_TYPE_EXTERNAL,               // 外部命令扩展实现播放器
        AUDIO_PLAYER_TYPE_MPLAYER,                // 封装 mplayer 实现播放器
    }AUDIO_PLAYER_TYPE_E;

public:

    AudioPlayer *create(AUDIO_PLAYER_TYPE_E type);     // 创建指定类型的播放器
    int destroy(AudioPlayer **ppAudioPlayer);          // 释放播放器

};

}

#endif

/**
******************************************************************************
* @文件        AudioManager.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "AudioMenager.h"
#include "../player/AudioPlayerExternal.h"
#include "../player/AudioPlayerMPlayer.h"

using namespace simple;

AudioPlayer *AudioManager::create(AUDIO_PLAYER_TYPE_E type)
{
    AudioPlayer *pAudioPlayer = NULL;

    printf("namespace simple: AudioManager->create()...\n");
    switch (type)
    {
        case AUDIO_PLAYER_TYPE_EXTERNAL:
            pAudioPlayer = new AudioPlayerExternal();
            break;

        case AUDIO_PLAYER_TYPE_MPLAYER:
            pAudioPlayer = new AudioPlayerMPlayer();
            break;

        default:
            return NULL;
    }

    return pAudioPlayer;
}

int AudioManager::destroy(AudioPlayer **ppAudioPlayer)
{
    printf("namespace simple: AudioManager->destroy()...\n");

    if (NULL == ppAudioPlayer || NULL == *ppAudioPlayer)
        return -1;

    delete (*ppAudioPlayer);
    *ppAudioPlayer = nullptr;

    return 0;
}

单元测试代码:具体关注 simpleTest()

/**
******************************************************************************
* @文件        test_AudioPlayer.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式单元测试
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "AudioPlayerInterface.h"

// 纯接口测试需要用到
#include "player/AudioPlayerMPlayer.h"
#include "player/AudioPlayerExternal.h"

// 简单工厂模式需要用到
#include "../Factory/simple/AudioMenager.h"

class TestAudioPlayer : public AudioPlayerEventMonitor
{
private:

        // 通过 AudioPlayerEventMonitor 继承
    virtual void onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent) override;
    void audioPlayerOps(AudioPlayer* pAudioPlayer);    // 音频播放器接口测试

    void interfaceTest(void);                          // 纯接口测试
    void simpleTest(void);                             // 简单工厂模式测试

public:

    void test(void);

};

/**
******************************************************************************
* @文件        test_AudioPlayer.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式单元测试
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#include <iostream>
#include "test_AudioPlayer.h"

// 播放器事件状态回调通知
void TestAudioPlayer::onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent)
{

}

// 音频播放器操作
void TestAudioPlayer::audioPlayerOps(AudioPlayer* pAudioPlayer)
{
    pAudioPlayer->setEventMonitor(this);
    pAudioPlayer->init(NULL);
    pAudioPlayer->setVolume(15);
    pAudioPlayer->play("test.mp3");
    pAudioPlayer->reset();
    pAudioPlayer->pause();
    pAudioPlayer->resume();
    pAudioPlayer->stop();
    pAudioPlayer->release();

    return ;
}

// 接口测试(业务逻辑代码中会暴露具体实现)
void TestAudioPlayer::interfaceTest(void)
{
    AudioPlayer* pAudioPlayer = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = new AudioPlayerMPlayer();
    audioPlayerOps(pAudioPlayer);
    delete pAudioPlayer;

    // 测试以调用外部命令的方式实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = new AudioPlayerExternal();
    audioPlayerOps(pAudioPlayer);
    delete pAudioPlayer;

    puts("-----------------------------------------------------------------------");
}

// 简单工厂设计模式测试(虽然不会暴露具体实现,但是每次增加一个具体实现都需要修改原有AudioManager代码)
void TestAudioPlayer::simpleTest(void)
{
    simple::AudioManager   mAudioManager;
    AudioPlayer            *pAudioPlayer = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = mAudioManager.create(simple::AudioManager::AUDIO_PLAYER_TYPE_MPLAYER);
    audioPlayerOps(pAudioPlayer);
    mAudioManager.destroy(&pAudioPlayer);

    // 测试以调用外部命令的方式实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = mAudioManager.create(simple::AudioManager::AUDIO_PLAYER_TYPE_EXTERNAL);
    audioPlayerOps(pAudioPlayer);
    mAudioManager.destroy(&pAudioPlayer);

    puts("-----------------------------------------------------------------------");
}

void TestAudioPlayer::test(void)
{
    puts("interface test ...");
    interfaceTest();

    puts("simple factort mode test ...");
    simpleTest();

    return;
}



interface test ...
-----------------------------------------------------------------------
AudioPlayerMPlayer()
AudioPlayerMPlayer: init()...
AudioPlayerMPlayer: setVolume() volume:15 ...
AudioPlayerMPlayer: play()...
AudioPlayerMPlayer: reset()...
AudioPlayerMPlayer: pause()...
AudioPlayerMPlayer: resume()...
AudioPlayerMPlayer: stop()...
AudioPlayerMPlayer: release()...
~AudioPlayerMPlayer()
-----------------------------------------------------------------------
AudioPlayerExternal()
AudioPlayerExternal: init()...
AudioPlayerExternal: setVolume() volume:15 ...
AudioPlayerExternal: play()...
AudioPlayerExternal: reset()...
AudioPlayerExternal: pause()...
AudioPlayerExternal: resume()...
AudioPlayerExternal: stop()...
AudioPlayerExternal: release()...
~AudioPlayerExternal()
-----------------------------------------------------------------------
simple factort mode test ...
-----------------------------------------------------------------------
namespace simple: AudioManager->create()...
AudioPlayerMPlayer()
AudioPlayerMPlayer: init()...
AudioPlayerMPlayer: setVolume() volume:15 ...
AudioPlayerMPlayer: play()...
AudioPlayerMPlayer: reset()...
AudioPlayerMPlayer: pause()...
AudioPlayerMPlayer: resume()...
AudioPlayerMPlayer: stop()...
AudioPlayerMPlayer: release()...
namespace simple: AudioManager->destroy()...
~AudioPlayerMPlayer()
-----------------------------------------------------------------------
namespace simple: AudioManager->create()...
AudioPlayerExternal()
AudioPlayerExternal: init()...
AudioPlayerExternal: setVolume() volume:15 ...
AudioPlayerExternal: play()...
AudioPlayerExternal: reset()...
AudioPlayerExternal: pause()...
AudioPlayerExternal: resume()...
AudioPlayerExternal: stop()...
AudioPlayerExternal: release()...
namespace simple: AudioManager->destroy()...
~AudioPlayerExternal()
-----------------------------------------------------------------------

从 AudioManager 类里面可以看到,创建何种类型的播放器,取决于 create() type 参数,这意味着每次新增加一个新的具体播放器实现类,就需要修改一次原有的 AudioManager 类定义,违反设计模式六大原则中的 “开闭原则”。因此引出工厂模式的进阶版 “工厂方法模式”。

通过将 AudioManager 进一步抽象化,每一个具体的播放器类都有一个 AudioManager 对应,需要使用哪个类,就实例化哪个 AudioManager 类。(AudioManager 命名在这里似乎不太合适)

AudioManager 不再实现具体的对象创建:

/**
******************************************************************************
* @文件        AudioManager.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#ifndef __AUDIO_MANAGER_METHOD_H
#define __AUDIO_MANAGER_METHOD_H

#include "../AudioPlayerInterface.h"

namespace method {

class AudioManager
{
public:

    virtual AudioPlayer* create() = 0;                        // 创建指定类型的播放器
    virtual int destroy(AudioPlayer **ppAudioPlayer) = 0;     // 释放播放器

};

}

#endif

MPlayer 播放器的 AudioManager:

/**
******************************************************************************
* @文件        AudioManagerMPlayer.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器(工厂方法设计模式)
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#ifndef __AUDIO_MANAGER_MPLAYER_H
#define __AUDIO_MANAGER_MPLAYER_H

#include "../AudioPlayerInterface.h"
#include "AudioMenager.h"

class AudioManagerMPlayer : public method::AudioManager
{
public:

    virtual AudioPlayer* create() override;                        // 创建指定类型的播放器
    virtual int destroy(AudioPlayer **ppAudioPlayer) override;     // 释放播放器

};

#endif

/**
******************************************************************************
* @文件        AudioManagerMPlayer.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器(工厂方法设计模式)
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "../player/AudioPlayerExternal.h"
#include "../player/AudioPlayerMPlayer.h"
#include "AudioMenager.h"
#include "AudioMenagerMPlayer.h"

AudioPlayer* AudioManagerMPlayer::create()
{
    printf("namespace method: AudioManagerMPlayer->create()...\n");
    return new AudioPlayerMPlayer();
}

int AudioManagerMPlayer::destroy(AudioPlayer **ppAudioPlayer)
{
    printf("namespace method: AudioManagerMPlayer->destroy()...\n");

    if (NULL == ppAudioPlayer || NULL == *ppAudioPlayer)
        return -1;

    delete (*ppAudioPlayer);
    *ppAudioPlayer = nullptr;

    return 0;
}

调用外部命令实现播放器的 AudioManager:

/**
******************************************************************************
* @文件        AudioManagerExternal.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器(工厂方法设计模式)
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#ifndef __AUDIO_MANAGER_EXTERNALE_H
#define __AUDIO_MANAGER_EXTERNALE_H

#include "../AudioPlayerInterface.h"
#include "AudioMenager.h"

class AudioManagerExternal : public method::AudioManager
{
public:

    virtual AudioPlayer* create() override;                        // 创建指定类型的播放器
    virtual int destroy(AudioPlayer **ppAudioPlayer) override;     // 释放播放器

};

#endif

/**
******************************************************************************
* @文件        AudioManagerExternal.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁指定类型的播放器(工厂方法设计模式)
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "../player/AudioPlayerExternal.h"
#include "../player/AudioPlayerMPlayer.h"
#include "AudioMenager.h"
#include "AudioMenagerExternal.h"

AudioPlayer* AudioManagerExternal::create()
{
    printf("namespace method: AudioManagerExternal->create()...\n");
    return new AudioPlayerExternal();
}

int AudioManagerExternal::destroy(AudioPlayer **ppAudioPlayer)
{
    printf("namespace method: AudioManagerExternal->destroy()...\n");

    if (NULL == ppAudioPlayer || NULL == *ppAudioPlayer)
        return -1;

    delete (*ppAudioPlayer);
    *ppAudioPlayer = nullptr;

    return 0;
}

单元测试代码

/**
******************************************************************************
* @文件        test_AudioPlayer.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式单元测试
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "AudioPlayerInterface.h"

// 纯接口测试需要用到
#include "player/AudioPlayerMPlayer.h"
#include "player/AudioPlayerExternal.h"

// 简单工厂模式需要用到
#include "../Factory/simple/AudioMenager.h"

// 工厂模式方法需要用到
#include "method/AudioMenager.h"
#include "../Factory/method/AudioMenagerMPlayer.h"
#include "../Factory/method/AudioMenagerExternal.h"

class TestAudioPlayer : public AudioPlayerEventMonitor
{
private:

    void audioPlayerOps(AudioPlayer* pAudioPlayer);       // 音频播放器接口测试

    void interfaceTest(void);                             // 纯接口测试
    void simpleTest(void);                                // 简单工厂模式测试
    void methodTest(void);                                // 工厂方法模式测试

public:

    void test(void);

    // 通过 AudioPlayerEventMonitor 继承
    virtual void onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent) override;

};

/**
******************************************************************************
* @文件        test_AudioPlayer.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式单元测试
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#include <iostream>
#include "test_AudioPlayer.h"

// 播放器事件状态回调通知
void TestAudioPlayer::onAudioPlayerEventMonitor(TAudioPlayerEvent* pEvent)
{

}

// 音频播放器操作
void TestAudioPlayer::audioPlayerOps(AudioPlayer* pAudioPlayer)
{
    pAudioPlayer->setEventMonitor(this);
    pAudioPlayer->init(NULL);
    pAudioPlayer->setVolume(15);
    pAudioPlayer->play("test.mp3");
    pAudioPlayer->reset();
    pAudioPlayer->pause();
    pAudioPlayer->resume();
    pAudioPlayer->stop();
    pAudioPlayer->release();

    return ;
}

// 接口测试(业务逻辑代码中会暴露具体实现)
void TestAudioPlayer::interfaceTest(void)
{
    AudioPlayer* pAudioPlayer = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = new AudioPlayerMPlayer();
    audioPlayerOps(pAudioPlayer);
    delete pAudioPlayer;

    // 测试以调用外部命令的方式实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = new AudioPlayerExternal();
    audioPlayerOps(pAudioPlayer);
    delete pAudioPlayer;

    puts("-----------------------------------------------------------------------");
}

// 简单工厂设计模式测试(虽然不会暴露具体实现,但是每次增加一个具体实现都需要修改原有AudioManager代码)
void TestAudioPlayer::simpleTest(void)
{
    simple::AudioManager    mAudioManager;
    AudioPlayer             *pAudioPlayer = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = mAudioManager.create(simple::AudioManager::AUDIO_PLAYER_TYPE_MPLAYER);
    audioPlayerOps(pAudioPlayer);
    mAudioManager.destroy(&pAudioPlayer);

    // 测试以调用外部命令的方式实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = mAudioManager.create(simple::AudioManager::AUDIO_PLAYER_TYPE_EXTERNAL);
    audioPlayerOps(pAudioPlayer);
    mAudioManager.destroy(&pAudioPlayer);

    puts("-----------------------------------------------------------------------");
}

// 工厂方法设计模式测试(虽然每次增加一个具体实现都不需要修改原有代码,但是却需要多增加一个工厂类)
void TestAudioPlayer::methodTest(void)
{
    method::AudioManager       *pAudioManager = NULL;
    AudioPlayer                *pAudioPlayer  = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioManager   = new AudioManagerMPlayer();
    pAudioPlayer    = pAudioManager->create();
    audioPlayerOps(pAudioPlayer);
    pAudioManager->destroy(&pAudioPlayer);
    delete pAudioManager;

    // 测试以调用外部命令的方式实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioManager   = new AudioManagerExternal();
    pAudioPlayer    = pAudioManager->create();
    audioPlayerOps(pAudioPlayer);
    pAudioManager->destroy(&pAudioPlayer);
    delete pAudioManager;

    puts("-----------------------------------------------------------------------");

}

void TestAudioPlayer::test(void)
{
    puts("interface test ...");
    interfaceTest();

    puts("simple factort mode test ...");
    simpleTest();

    puts("method factort mode test ...");
    methodTest();
    return;
}



interface test ...
-----------------------------------------------------------------------
AudioPlayerMPlayer()
AudioPlayerMPlayer: init()...
AudioPlayerMPlayer: setVolume() volume:15 ...
AudioPlayerMPlayer: play()...
AudioPlayerMPlayer: reset()...
AudioPlayerMPlayer: pause()...
AudioPlayerMPlayer: resume()...
AudioPlayerMPlayer: stop()...
AudioPlayerMPlayer: release()...
~AudioPlayerMPlayer()
-----------------------------------------------------------------------
AudioPlayerExternal()
AudioPlayerExternal: init()...
AudioPlayerExternal: setVolume() volume:15 ...
AudioPlayerExternal: play()...
AudioPlayerExternal: reset()...
AudioPlayerExternal: pause()...
AudioPlayerExternal: resume()...
AudioPlayerExternal: stop()...
AudioPlayerExternal: release()...
~AudioPlayerExternal()
-----------------------------------------------------------------------
simple factort mode test ...
-----------------------------------------------------------------------
namespace simple: AudioManager->create()...
AudioPlayerMPlayer()
AudioPlayerMPlayer: init()...
AudioPlayerMPlayer: setVolume() volume:15 ...
AudioPlayerMPlayer: play()...
AudioPlayerMPlayer: reset()...
AudioPlayerMPlayer: pause()...
AudioPlayerMPlayer: resume()...
AudioPlayerMPlayer: stop()...
AudioPlayerMPlayer: release()...
namespace simple: AudioManager->destroy()...
~AudioPlayerMPlayer()
-----------------------------------------------------------------------
namespace simple: AudioManager->create()...
AudioPlayerExternal()
AudioPlayerExternal: init()...
AudioPlayerExternal: setVolume() volume:15 ...
AudioPlayerExternal: play()...
AudioPlayerExternal: reset()...
AudioPlayerExternal: pause()...
AudioPlayerExternal: resume()...
AudioPlayerExternal: stop()...
AudioPlayerExternal: release()...
namespace simple: AudioManager->destroy()...
~AudioPlayerExternal()
-----------------------------------------------------------------------
method factort mode test ...
-----------------------------------------------------------------------
namespace method: AudioManagerMPlayer->create()...
AudioPlayerMPlayer()
AudioPlayerMPlayer: init()...
AudioPlayerMPlayer: setVolume() volume:15 ...
AudioPlayerMPlayer: play()...
AudioPlayerMPlayer: reset()...
AudioPlayerMPlayer: pause()...
AudioPlayerMPlayer: resume()...
AudioPlayerMPlayer: stop()...
AudioPlayerMPlayer: release()...
namespace method: AudioManagerMPlayer->destroy()...
~AudioPlayerMPlayer()
-----------------------------------------------------------------------
namespace method: AudioManagerExternal->create()...
AudioPlayerExternal()
AudioPlayerExternal: init()...
AudioPlayerExternal: setVolume() volume:15 ...
AudioPlayerExternal: play()...
AudioPlayerExternal: reset()...
AudioPlayerExternal: pause()...
AudioPlayerExternal: resume()...
AudioPlayerExternal: stop()...
AudioPlayerExternal: release()...
namespace method: AudioManagerExternal->destroy()...
~AudioPlayerExternal()
-----------------------------------------------------------------------

从 AudioManagerMPlayer 和 AudioManagerExternal 类就可以发现,”工厂方法模式“ 的缺陷在于每次新增一个播放器都需要创建新的 AudioManagerXxxxxx 类,较为繁琐。

另一种方式

还有一种使用方式,那就是提供一个创建音频播放器的方法,隐藏具体的实现方式,业务逻辑只在需要的时候创建并使用,例如默认可以提供 Mplayer 的方式实现音频播放器。后续维护或者有其它的需求时,Mplayer不满足,那么就可以另外实现,然后只需要修改 AudioManager 类的 create() 接口,即可完成替换而不需要修改业务逻辑代码。

/**
******************************************************************************
* @文件        AudioManager.h
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁音频播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/
#ifndef __AUDIO_MANAGER_SIMPLE_H
#define __AUDIO_MANAGER_SIMPLE_H

#include "../AudioPlayerInterface.h"

class AudioManager
{

public:

    AudioPlayer* create();                              // 创建播放器
    int destroy(AudioPlayer **ppAudioPlayer);           // 释放播放器

};

#endif

/**
******************************************************************************
* @文件        AudioManager.cpp
* @版本        V1.0.0
* @日期
* @概要        工厂设计模式示例代码 - 音频管理类的实现,用于创建和销毁音频播放器
* @作者        lmx
* @邮箱        lovemengx@qq.com
* @博客        https://me.csdn.net/lovemengx
******************************************************************************
**/

#include "AudioMenager.h"
#include "../player/AudioPlayerExternal.h"
#include "../player/AudioPlayerMPlayer.h"

AudioPlayer *AudioManager::create()
{
    return new AudioPlayerMPlayer();;
}

int AudioManager::destroy(AudioPlayer **ppAudioPlayer)
{
    printf("namespace simple: AudioManager->destroy()...\n");

    if (NULL == ppAudioPlayer || NULL == *ppAudioPlayer)
        return -1;

    delete (*ppAudioPlayer);
    *ppAudioPlayer = nullptr;

    return 0;
}

void TestAudioPlayer::simpleTest(void)
{
    simple::AudioManager       mAudioManager;
    AudioPlayer                *pAudioPlayer = NULL;

    // 测试以 mplayer 为基础实现的播放器
    puts("-----------------------------------------------------------------------");
    pAudioPlayer = mAudioManager.create();
    audioPlayerOps(pAudioPlayer);
    mAudioManager.destroy(&pAudioPlayer);
    puts("-----------------------------------------------------------------------");
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章